Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.68/40: Рейтинг темы: голосов - 40, средняя оценка - 4.68
0 / 0 / 1
Регистрация: 23.03.2013
Сообщений: 22
1

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

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

Author24 — интернет-сервис помощи студентам
Есть вот такая функция для =которую выполняют рабочие потоки
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), вылитает.
Вопрос почему?
И вообще= коректно ли давать множеству потоков одну и ту же рабочую функцию?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.08.2013, 21:07
Ответы с готовыми решениями:

Генерация случайных чисел несколькими потоками
необходимо реализовать генерацию случайных чисел с использованием нескольких потоков и выполнить ...

Использование одной пользовательской формы несколькими макросами
Я создал форму: 2 кнопки и Label. У меня есть 10 макросов. Могу ли я использовать одну эту форму...

Многопоточность (использование двумя потоками двух разных элементов одной формы)
На форме 2 RichTextBox, создается второй поток, оба потока выводят построчно индекс, который...

Работа с несколькими потоками
у меня вопрос, к тем кто работает с многопоточными приложениями у меня алгоритм такой: в основном...

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

Цитата Сообщение от Александр Макед Посмотреть сообщение
И вообще= коректно ли давать множеству потоков одну и ту же рабочую функцию?
Корректно.
Каждый поток получит свою копию локальных переменных функции.
0
0 / 0 / 1
Регистрация: 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;
}
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
31.08.2013, 22:18 4
Код, конечно, не сахар. Можете описать, в чем смысл данных вычислений ?
0
0 / 0 / 1
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 22:22  [ТС] 5
Цитата Сообщение от Убежденный Посмотреть сообщение
Код, конечно, не сахар. Можете описать, в чем смысл данных вычислений ?
Основной поток запускает X (1 < X <= 64) вспомогательных потоков. X - первый параметр командной строки.
Каждый из вспомогательных потоков бесконечно (с некоторой изменяющейся задержкой) добавляет в общий контейнер свой элемент.
При этом он удаляет самый старый элемент в случае, если тот был добавлен другим потоком или если количество элементов в контейнере > Y ( Y - второй параметр командной строки).
Основной поток ожидает любого ввода из командной строки (например нажатия на Enter ).
После получения ввода из командной строки основной поток должен распечатать статистику и максимальное зарегистрированное количество элементов в контейнере.

командную строку пока не подключал=простой ввод с консоли.
0
1443 / 1326 / 131
Регистрация: 20.03.2009
Сообщений: 4,689
Записей в блоге: 11
31.08.2013, 22:34 6
Александр Макед, ты в курсе что rand нельзя использовать из несколько потоков?
Цитата Сообщение от Убежденный Посмотреть сообщение
Корректно.
только в случае отсутствия побочных эффектов.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
31.08.2013, 22:36 7
Цитата Сообщение от Dmitriy_M Посмотреть сообщение
rand нельзя использовать из несколько потоков?
Это еще почему ?
1
0 / 0 / 1
Регистрация: 23.03.2013
Сообщений: 22
31.08.2013, 22:58  [ТС] 8
проблема с контейнером, он все время ругается на итератор- то его инкрементить нельзя , то декрементить то разименовывать. если в функции порожденных потоков работу с контейнером убрать, работает аж бегом, а так не хочет.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 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 / 1
Регистрация: 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;
}
ну в общем можно и так, только ,как я понимаю, так будет медленнее работать, так как переходы в методы класса жрут ресурсы процессора.
но в любом случае спасибо, поменяю малость дизайн, а там видно будет.
0
1443 / 1326 / 131
Регистрация: 20.03.2009
Сообщений: 4,689
Записей в блоге: 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().
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 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 потоками.
0
01.09.2013, 10:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.09.2013, 10:09
Помогаю со студенческими работами здесь

Выигрышь в скорости с несколькими потоками?..
Программу (связана с рассчётом) написал в двух видах: последовательном и многопоточном.. В случае с...

Запись в файл несколькими потоками
Помогите решить задачу Создать k потоков, которые одновременно пишут в один и тот же файл символы:...

Закачка файла несколькими потоками.
Кто знает, как на Java посылать на сервер HTML-запрос на скачивание части файла? Большая просьба...

Запись данных в файл несколькими потоками.
Как на Java реализовать запись в файл несколькими потоками? К примеру, имеется файл размером 3Мб,...


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru