Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Александр Макед
0 / 0 / 0
Регистрация: 23.03.2013
Сообщений: 22
#1

Использование несколькими потоками одной функции - C++

31.08.2013, 21:07. Просмотров 716. Ответов 11
Метки нет (Все метки)

Есть вот такая функция для =которую выполняют рабочие потоки
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
DWORD WINAPI ThreadFunc(void *pV)
{   
    Data* pD = (Data*)pV;
    int n, iSleeping(0), MaxCountInConteiner(0);
    n = iGlobal++;
    cout<<"\ntut j:"<<n<<endl<<endl;
 
    for(;;)
    {
        WaitForSingleObject(CreEvent, INFINITE);
        if(pD->Flag == true){
            pD->CountElement = MaxCountInConteiner;
            cout<<"=)threadFUNC="<<n<<endl;
            SetEvent(hArEvent[n]);
            return 0;
        }
        
        if(pD->iDeq.size() < pD->LimitsToEnter){
            ++MaxCountInConteiner;
            pD->iDeq.push_back(n*100);
            
            if(pD->iDeq.front() != n*100)//если добавил не этот поток
            {
                cout<<"aaaaaaaaaa"<<endl;
                --MaxCountInConteiner;
                pD->iDeq.pop_front();
            }
        }
        else
        {
            cout<<"bbbbbbbbbbbb"<<endl;
            pD->iDeq.push_back(n*100);
            pD->iDeq.pop_front();
        }
        cout<<"n="<<n<<endl;
        SetEvent(CreEvent);
        iSleeping = rand()%300;
        Sleep(iSleeping/*/pD->CountThread*/);//если не спать то завершается до вывода статистики
    }
Потоки запускаются из главного потока-предка. который создается и запускается в main.
при длительной работе(множестве вставок/удалений)(потоков 50), вылитает.
Вопрос почему?
И вообще= коректно ли давать множеству потоков одну и ту же рабочую функцию?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
31.08.2013, 21:07
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Использование несколькими потоками одной функции (C++):

можно ли в с++ вызвать переменную из одной функции в другую т.е. мы переменну задали в одной функции а использовали в другой... и как это реализовать? - C++
можно ли в с++ вызвать переменную из одной функции в другую т.е. мы переменну задали в одной функции а использовали в другой... и как это...

Функции работы с потоками - C++
На WInAPI есть функции приостановление и восстановление потоков - SuspendThread() и ResumeThread() Вопрос:есть ли что нибудь подобное в...

Подскажите библиотеки, функции по управлению потоками - C++
Прошу помогите! Подскажите библиотеки, функции по управлению потоками( созданию) либо какую литературу.Которые применяются в visual studio...

Использование одной переменной - C++
У меня дано два оператора n1=dist*dist; n2=dist/dist; хочу использовать одну переменную n которая принимала бы два эти...

Использование одной константы в нескольких файлах - C++
Пишу примитивную игру, в которой игрок ходит по прямоугольному полю и встречает монстров. Решил разделить разросшийся cpp-файл на...

Использование структуры с двумя полями и одной функцией - C++
Напишите программу, в которой используется структура с двумя полями и одной функцией. Одно поле имеет тип double, другое тип int. Функция...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Убежденный
Системный программист
Эксперт С++
15504 / 7002 / 1105
Регистрация: 02.05.2013
Сообщений: 11,436
Завершенные тесты: 1
31.08.2013, 21:26 #2
Цитата Сообщение от Александр Макед Посмотреть сообщение
при длительной работе(множестве вставок/удалений)(потоков 50), вылитает.
Вопрос почему?
Нужен полный код.

Цитата Сообщение от Александр Макед Посмотреть сообщение
И вообще= коректно ли давать множеству потоков одну и ту же рабочую функцию?
Корректно.
Каждый поток получит свою копию локальных переменных функции.
Александр Макед
0 / 0 / 0
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 22:03  [ТС] #3
Цитата Сообщение от Убежденный Посмотреть сообщение
Нужен полный код.



Корректно.
Каждый поток получит свою копию локальных переменных функции.
вот весь код

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
CRITICAL_SECTION main_g_cs;
static HANDLE MainThread, CreThread ,hArThread[MAX_THREAD];
static HANDLE MainEvent,    CreEvent ,hArEvent[MAX_THREAD];
static int iGlobal(0) ;
 
DWORD WINAPI CreateThreadFunc(void *pV);
DWORD WINAPI ThreadFunc(void *pV);
 
struct Data
{
    bool Flag;
    deque<int> iDeq;
    unsigned int LimitsToEnter;
    unsigned int CountThread;
    /*static */unsigned int CountElement;
    int iAr[MAX_THREAD];
    
    Data():Flag(false), CountElement(0){}
};
 
class Rabotnik
{
    //зделать чтоб нельзя было создать боьше 1 обьекта
    Data* pData;
    static Rabotnik* Self;
 
    Rabotnik()
    {
        pData = new Data();
    }
    ~Rabotnik()
    {
        delete pData;
    }
    Rabotnik& operator=(const Rabotnik);
    Rabotnik(const Rabotnik& Root);
public:
    static Rabotnik* CreateFunction()
    {
        if(!Self)
            Self = new Rabotnik();
 
        return Self;
    }
    static void DeleteFunction()
    {
        if(Self)
            delete Self;
    }
    int MainThreadFunc()
    {
            //InitializeCriticalSection(&main_g_cs);
        MainEvent = CreateEvent(0, TRUE, FALSE, L"CreateEventForMainThread1");
        DWORD dw = 0;
        MainThread = CreateThread(0, 0, CreateThreadFunc, pData, /*CREATE_SUSPENDED*/0, &dw);
        WaitForSingleObject(MainEvent, INFINITE);
            //EnterCriticalSection(&main_g_cs);
 
        cout<<"=)MAINTHREADfunc"<<endl;
        
            //DeleteCriticalSection(&main_g_cs);
 
        return 0;
    }
};
 
Rabotnik* Rabotnik::Self = 0;
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    {
    Rabotnik *pRab(Rabotnik::CreateFunction());
    pRab->MainThreadFunc();
    Rabotnik::DeleteFunction();
    }
    if(_CrtDumpMemoryLeaks())
        cout<<"MemoryLeaks!!!"<<endl;
 
    cout<<"=((main"<<endl;
 
    return 0;
}
 
 
DWORD WINAPI CreateThreadFunc(void *pV)
{   
    Data* pD = (Data*)pV;
 
    int CountThreadCreate, LimitsToenter;
    CreEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    do{
        cout<<"Enter count of thread (amount must be greater than 0): "<<endl;
        cin>>CountThreadCreate;
    }
    while(1 > CountThreadCreate || CountThreadCreate > 64);
    pD->CountThread = CountThreadCreate;
 
    do{
        cout<<"Enter Limits of entering (amount must be greater than 0): "<<endl;
        cin>>LimitsToenter;
        
    }while(LimitsToenter < 1);
    pD->LimitsToEnter = LimitsToenter;
 
    //DWORD dw2 = 0;
    for(int i = 0; i < pD->CountThread; i++)
    {
        hArEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
        pD->iAr[i] = i; 
        hArThread[i] = CreateThread(0, 0, ThreadFunc, pD, /*CREATE_SUSPENDED*/0, /*&dw2*/0);
    }
 
    char CoEx('c'); 
    cout<<"For stop press any key..."<<endl;
    SetEvent(CreEvent);
    CoEx = _getch();
 
    if(CoEx != 'c')
        pD->Flag = true;
 
    WaitForMultipleObjects(pD->CountThread, hArEvent, TRUE, INFINITE);
    
    deque<int>::iterator iTerDeq;   
    if(pD->iDeq.size() > 0)
    {
        cout<<"Max element in conteiner == "<<pD->CountElement<<"==!!"<<endl<<endl;
        for(iTerDeq = pD->iDeq.begin(); iTerDeq  != pD->iDeq.end(); iTerDeq++)
            cout<<"*iTerDeq = "<<*iTerDeq<<endl;
    }
    else
        cout<<"Conteiner is empty =("<<endl;    
    
    SetEvent(MainEvent);
    //LeaveCriticalSection(&main_g_cs);
    cout<<"=))))))CreateThread"<<endl;
    return 0;
}
 
DWORD WINAPI ThreadFunc(void *pV)
{   
    Data* pD = (Data*)pV;
    int n, iSleeping(0), MaxCountInConteiner(0);
    n = iGlobal++;
    cout<<"\ntut j:"<<n<<endl<<endl;
 
    for(;;)
    {
        WaitForSingleObject(CreEvent, INFINITE);
        if(pD->Flag == true){
            pD->CountElement = MaxCountInConteiner;
            cout<<"=)threadFUNC="<<n<<endl;
            SetEvent(hArEvent[n]);
            return 0;
        }
        
        if(pD->iDeq.size() < pD->LimitsToEnter){
            ++MaxCountInConteiner;
            pD->iDeq.push_back(n*100);
            
            if(pD->iDeq.front() != n*100)//если добавил не этот поток
            {
                cout<<"aaaaaaaaaa"<<endl;
                --MaxCountInConteiner;
                pD->iDeq.pop_front();
            }
        }
        else
        {
            cout<<"bbbbbbbbbbbb"<<endl;
            pD->iDeq.push_back(n*100);
            pD->iDeq.pop_front();
        }
        cout<<"n="<<n<<endl;
        SetEvent(CreEvent);
        iSleeping = rand()%300;
        Sleep(iSleeping/*/pD->CountThread*/);//если не спать то завершается до вывода статистики
    }
    return 0;
}
Убежденный
Системный программист
Эксперт С++
15504 / 7002 / 1105
Регистрация: 02.05.2013
Сообщений: 11,436
Завершенные тесты: 1
31.08.2013, 22:18 #4
Код, конечно, не сахар. Можете описать, в чем смысл данных вычислений ?
Александр Макед
0 / 0 / 0
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 22:22  [ТС] #5
Цитата Сообщение от Убежденный Посмотреть сообщение
Код, конечно, не сахар. Можете описать, в чем смысл данных вычислений ?
Основной поток запускает X (1 < X <= 64) вспомогательных потоков. X - первый параметр командной строки.
Каждый из вспомогательных потоков бесконечно (с некоторой изменяющейся задержкой) добавляет в общий контейнер свой элемент.
При этом он удаляет самый старый элемент в случае, если тот был добавлен другим потоком или если количество элементов в контейнере > Y ( Y - второй параметр командной строки).
Основной поток ожидает любого ввода из командной строки (например нажатия на Enter ).
После получения ввода из командной строки основной поток должен распечатать статистику и максимальное зарегистрированное количество элементов в контейнере.

командную строку пока не подключал=простой ввод с консоли.
Dmitriy_M
1342 / 1223 / 112
Регистрация: 20.03.2009
Сообщений: 4,406
Записей в блоге: 11
31.08.2013, 22:34 #6
Александр Макед, ты в курсе что rand нельзя использовать из несколько потоков?
Цитата Сообщение от Убежденный Посмотреть сообщение
Корректно.
только в случае отсутствия побочных эффектов.
Убежденный
Системный программист
Эксперт С++
15504 / 7002 / 1105
Регистрация: 02.05.2013
Сообщений: 11,436
Завершенные тесты: 1
31.08.2013, 22:36 #7
Цитата Сообщение от Dmitriy_M Посмотреть сообщение
rand нельзя использовать из несколько потоков?
Это еще почему ?
Александр Макед
0 / 0 / 0
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 22:58  [ТС] #8
проблема с контейнером, он все время ругается на итератор- то его инкрементить нельзя , то декрементить то разименовывать. если в функции порожденных потоков работу с контейнером убрать, работает аж бегом, а так не хочет.
Убежденный
Системный программист
Эксперт С++
15504 / 7002 / 1105
Регистрация: 02.05.2013
Сообщений: 11,436
Завершенные тесты: 1
31.08.2013, 23:20 #9
А нельзя ли это все переписать в более простом стиле ?
Например (ПСЕВДОКОД) :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int main()
{
    control Control; // Некий класс для управления потоками.
 
    HANDLE *pThreadHandles = new HANDLE[NumThreads];
 
    // Создаем столько-то потоков и синхронно стартуем их.
 
    for (int i = 0; i < NumThreads; ++i)
    {
        pThreadHandles[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, &Control, 0, NULL);
    }
 
    Control.start();
 
    // Ждем команды пользователя и даем потокам команду "завершить".
    _getch();
    Control.stop();
 
    // Ожидание завершения.
 
    WaitForMultipleObjects(NumThreads, pThreadHandles, TRUE, INFINITE); 
 
    for (int i = 0; i < NumThreads; ++i)
    {
        CloseHandle(pThreadHandles[i]);
    }
 
    delete [] pThreadHandles;
 
    // Здесь обработка результатов.
    // ...
 
    return 0;
}


Ну а функция потока могла быть примерно такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
unsigned int _stdcall ThreadProc(void *pParam)
{
    control *pCtrl = (control *)pParam;
    DWORD const ThreadId = GetCurrentThreadId(); // Получаем ID текущего потока.
 
    pCtrl->wait_for_start(); // Ждем сигнала "старт".
 
    for (;;)
    {
        if (false != pCtrl->check_for_quit()) // Проверка на завершение.
        {
            break;
        }
 
        Sleep(rand() % 300); // Рандомная задержка.
        
        // Синхронизация доступа к deque (например, на основе CRITICAL_SECTION или spin-lock).
 
        scoped_lock_t ScopedLock(pCtrl->SyncObject);
 
        // Помещаем новый элемент в контейнер.
        item NewItem = {ThreadId};
        pCtrl->Deque.push_back(NewItem);
        
        // Проверка на переполнение.
 
        if (pCtrl->Deque.size() > MaxItems)
        {
            pCtrl->Deque.pop_front();
        }
        
        // Проверка на то, что элемент в голове был вставлен другим потоком.
 
        else if (false == pCtrl->Deque.empty())
        {
            if (ThreadId != pCtrl->Deque.front().ThreadId)
            {
                pCtrl->Deque.pop_front();
            }
        }        
    }
 
    return 0;
}
Александр Макед
0 / 0 / 0
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 23:44  [ТС] #10
Цитата Сообщение от Убежденный Посмотреть сообщение
А нельзя ли это все переписать в более простом стиле ?
Например (ПСЕВДОКОД) :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int main()
{
    control Control; // Некий класс для управления потоками.
 
    HANDLE *pThreadHandles = new HANDLE[NumThreads];
 
    // Создаем столько-то потоков и синхронно стартуем их.
 
    for (int i = 0; i < NumThreads; ++i)
    {
        pThreadHandles[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, &Control, 0, NULL);
    }
 
    Control.start();
 
    // Ждем команды пользователя и даем потокам команду "завершить".
    _getch();
    Control.stop();
 
    // Ожидание завершения.
 
    WaitForMultipleObjects(NumThreads, pThreadHandles, TRUE, INFINITE); 
 
    for (int i = 0; i < NumThreads; ++i)
    {
        CloseHandle(pThreadHandles[i]);
    }
 
    delete [] pThreadHandles;
 
    // Здесь обработка результатов.
    // ...
 
    return 0;
}


Ну а функция потока могла быть примерно такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
unsigned int _stdcall ThreadProc(void *pParam)
{
    control *pCtrl = (control *)pParam;
    DWORD const ThreadId = GetCurrentThreadId(); // Получаем ID текущего потока.
 
    pCtrl->wait_for_start(); // Ждем сигнала "старт".
 
    for (;;)
    {
        if (false != pCtrl->check_for_quit()) // Проверка на завершение.
        {
            break;
        }
 
        Sleep(rand() % 300); // Рандомная задержка.
        
        // Синхронизация доступа к deque (например, на основе CRITICAL_SECTION или spin-lock).
 
        scoped_lock_t ScopedLock(pCtrl->SyncObject);
 
        // Помещаем новый элемент в контейнер.
        item NewItem = {ThreadId};
        pCtrl->Deque.push_back(NewItem);
        
        // Проверка на переполнение.
 
        if (pCtrl->Deque.size() > MaxItems)
        {
            pCtrl->Deque.pop_front();
        }
        
        // Проверка на то, что элемент в голове был вставлен другим потоком.
 
        else if (false == pCtrl->Deque.empty())
        {
            if (ThreadId != pCtrl->Deque.front().ThreadId)
            {
                pCtrl->Deque.pop_front();
            }
        }        
    }
 
    return 0;
}
ну в общем можно и так, только ,как я понимаю, так будет медленнее работать, так как переходы в методы класса жрут ресурсы процессора.
но в любом случае спасибо, поменяю малость дизайн, а там видно будет.
Dmitriy_M
1342 / 1223 / 112
Регистрация: 20.03.2009
Сообщений: 4,406
Записей в блоге: 11
31.08.2013, 23:49 #11
Цитата Сообщение от Убежденный Посмотреть сообщение
Это еще почему ?
Потому что не thread-safe.
Описание с http://www.cplusplus.com/
The function accesses and modifies internal state objects, which may cause data races with concurrent calls to rand or srand.

Some libraries provide an alternative function that explicitly avoids this kind of data race: rand_r (non-portable).

C++ library implementations are allowed to guarantee no data races for calling this function.
В POSIX об этом сказано явно
The function rand() is not reentrant or thread-safe, since it uses hidden state that is modified on each call. This might just be the seed value to be used by the next call, or it might be something more elaborate. In order to get reproducible behavior in a threaded application, this state must be made explicit; this can be done using the reentrant function rand_r().
Убежденный
Системный программист
Эксперт С++
15504 / 7002 / 1105
Регистрация: 02.05.2013
Сообщений: 11,436
Завершенные тесты: 1
01.09.2013, 10:09 #12
В Visual C++ стандартные функции уже много лет как thread-safe.
Library Support for Multithreading
The Multithread C Libraries: LIBCMT.LIB and MSVCRT.LIB

The support library LIBCMT.LIB is a reentrant library for creating multithread programs.
The MSVCRT.LIB library, which calls code in the shared MSVCRT70.DLL, is also reentrant.
Вот, к примеру, что написано про функцию strtok:
strtok, _strtok_l, wcstok, _wcstok_l, _mbstok, _mbstok_l
Each function uses a thread-local static variable for parsing the string into tokens.
Therefore, multiple threads can simultaneously call these functions without undesired effects.
However, within a single thread, interleaving calls to one of these functions is highly likely to
produce data corruption and inaccurate results. When parsing multiple strings, finish parsing one
string before parsing the next.
А это про srand:
srand
The srand function sets the starting point for generating a series of pseudorandom integers in the current thread.
У каждого потока своя копия "состояния" (через TLS), поэтому в Visual C++ такие
функции, как rand, можно без всяких опасений использовать в разных потоках.

Цитата Сообщение от Александр Макед Посмотреть сообщение
так будет медленнее работать, так как переходы в методы класса жрут ресурсы процессора.
Гадание на кофейной гуще.
Переход в метод класса - это, грубо говоря, один дополнительный call.
И код метода запросто может быть встроен по месту вызова. Так что каких-то
дополнительных накладных расходов там ноль без палочки. А вот ожидание на
объектах ядра (event) - вот это действительно дорогая операция, особенно для
сценария с 50 потоками.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.09.2013, 10:09
Привет! Вот еще темы с ответами:

Возвращение результата функции bool и использование его в функции main() - C++
У меня есть функция bool, которая имеет вид: bool Pisos(int row, int place) { if (...) return true; else return false;...

Ввод данных в функции конструктора и использование их в перегруженной функции - C++
Вот собственно код, как его исправить, что бы не было ошибки. Пишет что переменные не объявлены. Это вполне естественно. Но как сделать...

Дано строка, состоящая из русских слов, разделенных пробелами (одним или несколькими). ​​Определить количество слов, которые заканчиваются одной и той - C++
Дано строка, состоящая из русских слов, разделенных пробелами (одним или несколькими). ​​Определить количество слов, которые заканчиваются...

Использование функции как параметра другой функции - C++
В задании указано, что функция P прибавляет значение функции ff к элементу массива, если он входит в промежуток от C до D, которые вводятся...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
01.09.2013, 10:09
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru