Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.87/30: Рейтинг темы: голосов - 30, средняя оценка - 4.87
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114

Многопоточность, _beginthreadex, ошибка ntdll.dll

28.10.2016, 00:26. Показов 7459. Ответов 70
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, собственно сабж.

Посмотрите пожалуйста комментарии в коде. Как исправить ситуацию, не правильно запускаются потоки?

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
 unsigned __stdcall potok(void* Param)
 {
//Собственно тут код может быть любой на частоту появления ошибки вообще никак не влияет,
// я Комментировал вообще все подряд, все равно лезет ошибка
 
     static int *p = (int*)Param;
 
     char buffer[100];
     wsprintf(buffer, "%u", *p);
     MessageBox(0, buffer, "", 0); 
 
     delete[] buffer;
 
     _endthreadex(0);
     return 0;
 }
 
int main()
{
    for (int i = 0; i < 50; i++)
    {
//      Sleep(900); // Если ставить паузу между запусками потоков, то проблема появляется значительно реже,
              // но появляется так, или иначе в любом случае, без паузы у меня в9 из 10 ловится ошибка.
 
        try
        {
            _beginthreadex(NULL, 0, &potok, (void*)&i, 0, NULL);  
        }
    
        catch (char *str)
        {
            printf("Error '%s'!\n", str);
        }
    }
 
    _endthreadex(0);
return 0;
}
При выполнение этого кода, вылетает ошибка
Вызвано исключение по адресу 0x77456D39 (ntdll.dll) в CSmtp.exe: 0xC0000005: нарушение прав доступа при записи по адресу 0x00000014.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
28.10.2016, 00:26
Ответы с готовыми решениями:

Вызвано исключение по адресу 0x772C09D6 (ntdll.dll)
Здравствуйте. Имеется проблема: при добавлении данного перечня заголовков в VS (всех вместе или каждого по отдельности) компиляция...

Исключение по адресу 0x77785BE7 (ntdll.dll) в lagranz_interpolution.exe: 0xC0000005
Вызвано исключение по адресу 0x77785BE7 (ntdll.dll) в lagranz_interpolution.exe: 0xC0000005: нарушение прав доступа при чтении по адресу...

При запуске своей проги на Windows 7, ругается на ntdll.dll
Прогу пишу в BDS2006, а проблема по всей видимости из-за того, что запускать её пришлось в ОС x64... Подскажите (желательно срочно -...

70
nd2
3438 / 2817 / 1249
Регистрация: 29.01.2016
Сообщений: 9,430
03.11.2016, 07:58
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от lostandleft Посмотреть сообщение
Может быть я ошибся, и не до конца понял суть проблемы
Проблема тут, как мне видится, такая. В каждом потоке создаётся MessageBox, поток после этого останавливается и начинается цикл обработки событий, связанный с созданным MessageBox, при нажатии на Ok происходит выход из цикла, поток завершает работу, основной поток ждёт завершения всех потоков. Тут всё нормально. Теперь ты хочешь к этому всему прикрутить таймер, который, после истечения определённого времени, должен завершать цикл обработки событий MessageBox или убивать поток, в котором этот MessageBox создан. И таймер ты пытаешься создать средствами языка С++, в котором нет никаких методов для доступа к MessageBox, и к его циклу обработки событий. Поэтому, как MessageBox, средствами языка С++, сообщить, что пора заканчивать? Я мало знаком с потоками С++ (больше Qt-овскими пользуюсь), может и ошибаюсь, но не нашёл способа и убить поток, в котором работает MessageBox. Единственное что пришло на ум - это вброс, через определённое время, исключения.
Как-то, так:
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
mutex MUTEX;
int thread_count = 0;
 
void timer(int SecPause)
{
    std::this_thread::sleep_for(std::chrono::seconds(SecPause));
    throw std::runtime_error("Quit");
}
 
void f1(void* n)
{
    try
    {
        thread time(timer, 7);
        time.detach();
    }
    catch (const std::runtime_error& e)
    {
        return;
    }
 
    int p = (int)n;
    {
        std::lock_guard<std::mutex> _(MUTEX);
        ++thread_count;
    }
 
     char buffer[100];
     wsprintf(buffer, "%u", p);
     MessageBox(0, buffer, "", 0);
 
     {
        std::lock_guard<std::mutex> _(MUTEX);
        std::cout << "thread " << p << " working\n";
     }
}
 
 
int main()
{
    const int N = 3; // Количество потоков
    thread tt[N];
 
    for (int i = 0; i < N; i++)
    {
        cout << "Message from main Start_" << i << endl;
 
        tt[i] = thread(&f1, (void*)i);
        cout << "Potok" << i << " nat hand_" << tt[i].native_handle() << endl;
    }
 
    for (int i = 0; i < N; i++)
    {
 
        std::cout << "TRY TO FIN CORRECTLY " << i<<" \n";
        if (tt[i].joinable())
        {
            try
            {
                std::cout << "potok" << i << " nat hand_" << tt[i].native_handle() << endl;
                tt[i].join();
            }
            catch (int Error)
            {
                std::cout << "Sorry Error Here Destroy_"<<Error<< endl;
 
            }
        }
    }
    return 0;
}
1
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
03.11.2016, 09:46  [ТС]
Цитата Сообщение от nd2 Посмотреть сообщение
Поэтому, как MessageBox, средствами языка С++, сообщить, что пора заканчивать?
Спасибо за попытку разобраться, MsgBox Это просто вариант и некий шаблон для меня, в реальном приложении конечно будет другая функция, но, так или иначе это хороший вариант для отладки приложения именно по той причине что сложно выявить проблему. Ведь нет никакой гарантии что в реальной функции не сработает какое-нибудь исключение или не вылетет непредвиденная ошибка, которую невозможно будет отследить в параллельном потоке.
Поэтому такое извращение и делаю, может быть и не правильно но со своей колокольни видится именно так.
Спасибо за помощь, попробую поизголяться.
Вообще делать поток detach, не хотелось совершенно, желание было нормально завершать потоки через Join.
В принципе и в моем кривом коде если включить detach, то вроде бы все работает нормально.
Но мне не нравится, вообще нет никакого даже мнимого контроля за потоком тогда.
Если я правильно понимаю Max Dark, то нужно делать нормальный деструктор, чтоб не было проблем.
НО пока я не догоняю как именно это сделать...попробую поковырять, если не получится, опять буду просить о помощи.
0
nd2
3438 / 2817 / 1249
Регистрация: 29.01.2016
Сообщений: 9,430
03.11.2016, 18:21
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

lostandleft, проблема в том, что ты пытаешься совместить вещи из разных областей: объект из WinAPI и уеравление им через потоки и методы С++. Если уж MessageBox, то и реализуй это через потоки и методы WinAPI (как ты сначала и пытался это делать), если потоки С++, то без объектов и методов из WinAPI.
Или используй другие инструменты, в которых есть возможность работы с потоками (типа Qt, в котором есть и свои MessageBox и свои потоки, и, поэтому, там проблем совместимости не будет).
1
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
03.11.2016, 22:27  [ТС]
Цитата Сообщение от nd2 Посмотреть сообщение
lostandleft, проблема в том, что ты пытаешься совместить вещи из разных областей:
Цитата Сообщение от nd2 Посмотреть сообщение
как ты сначала и пытался это делать
_beginthreadex и WaitForMultipleObjects не работают ошибка я её уже цитировал, если есть возможность подсказать как исправить прошу, код есть выше.
WaitForSingleObjects не работает так как надо - Это вообще не многопоточность, не понимаю для кого или для чего это сделано, какое-то псевдомногопоточие, пока не дождется окончания работы одного потока не запускается другой, бред.
Аналогично std::async, те же яйца только в профиль, проблема та-же самая.

Только нормальные нативные threds более менее работают.
И в общем то проблему уже почти решил, через часик код выложу, для ознакомления, может критика будет.
Да, кстати nd2, твой вариант кода тоже с ошибкой выплевывается, как ни крути.
0
nd2
3438 / 2817 / 1249
Регистрация: 29.01.2016
Сообщений: 9,430
03.11.2016, 22:41
Цитата Сообщение от lostandleft Посмотреть сообщение
твой вариант кода тоже с ошибкой выплевывается, как ни крути.
С какой ошибкой? Да это и не вариант, это так, размышления на тему: совместить несовместимое.

Добавлено через 3 минуты
Цитата Сообщение от lostandleft Посмотреть сообщение
_beginthreadex и WaitForMultipleObjects не работают ошибка я её уже цитировал, если есть возможность подсказать как исправить прошу, код есть выше.
Убежденный написал насчёт ошибок. С вопросами по WinAPI туда: https://www.cyberforum.ru/win-api/
0
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
04.11.2016, 01:16  [ТС]
Цитата Сообщение от nd2 Посмотреть сообщение
С вопросами по WinAPI туда
Я что тут мешаю?
Написал же уже трижды, что проблему решить не могу стандартными средвами.
Если подсказать не можешь как решить, не нужно меня определять по темам.
Я эту уже начал, мне тут удобнее постить.
Сейчас код закончу опубликую, может кому пригодится.
Повторюсь, решение нашел, будет желание его (решение) унизить, буду рад посмотреть.
Но пока что вроде бы как работает все сносно и именно так как нужно.

Добавлено через 2 часа 27 минут
И так, парни я решил все, есть подозрения что Max Dark, увидел все косяки еще вчера, и причину появления ошибки, и как её решить, но почему-то не подсказал и заставил меня ковыряться самостоятельно...ну нет худа без добра, разобрался от части.
Сделал в общем как мне кажется нормальное решение.
Конечно код очень косноязычен, и если кто-то пожелает сделать его более читаемым, обернет в классы и как-то улучшит буду очень рад и признателен.
Но и на данный момент оно работает от части так, как нужно.
Все равно вылетает ошибка если запускать безумное количество потоков, больше 500, при чем ошибка вылетает если обильно тыкать на ОК очень часто в сообщениях.
При этом ошибку поймать у меня в дебагере не получается студия предлагает только дезасемблированный вариант кода, который для меня более чем непонятен.
При запуске относительно разумного числа потоков все работает нормально. Ну, или на ОК не тыкать то тоже все работает без проблем. Могу предположить что где-то потоки используют таки общие ресурсы, а где найти не могу.


Но алгоритм вкратце работает так:
Каждый поток после запуска делает запись в вектор своего ID.
Дальше после того, как поток закончил свои действия он удаляет из вектора свой ID.
Основная функция проверяет наличие ID в векторе и если находит, то терминирует процесс, если же нет, то нормально удаляет его через join.

Детальный код с из-лишними комментариями ниже:

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
182
183
184
185
186
187
188
#include <mutex>
#include <chrono>
#include <thread>
#include <iostream>
#include <Windows.h>
#include <condition_variable>
 
#include <vector>
#include <algorithm>
#include <iterator>
 
using namespace std;
mutex MUTEX;
 
const int N = 500; // Количество потоков
int SecPause = 10; // Устанавливаем таймер, таймаут
 
 
int thread_count = 0;
bool time_to_quit = false;
std::condition_variable cv;
std::vector<thread::id> thread_id;
 
void f1(void* n)
{
    int p = (int)n;
    //тут задаем вводные, чтобы не получилось ситуации при которой время операции дочернего потока получилась больше длины основного
    int pause = 0;
    int counts = 1000;
    int PauseMillisec = SecPause * 1000 - counts;
 
    //Получаем ID потока
    std::thread::id this_id = std::this_thread::get_id();
    
    {
        std::lock_guard<std::mutex> _(MUTEX);
        //Записываем ID потока в вектор, увеличиваем счетчик потоков
        thread_id.push_back(this_id);
        ++thread_count;
    }
    ///////////////////////////тут делаем что-то///////////////////
    char buffer[100];
    wsprintf(buffer, "%u", p);
    MessageBox(0, buffer, "", 0);
 
    while (true && pause < PauseMillisec)
    {
        pause += counts;
        {
            std::lock_guard<std::mutex> _(MUTEX);
            std::cout << "thread " << p << " working\n";
        }
        ///////////////////////////////////////////////////////////
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        ///////////////////////////////////////////////////////////
        std::lock_guard<std::mutex> _(MUTEX);
        if (time_to_quit)
        {
            break;
            
        }
    }
    ///////////////////////////тут делаем что-то///////////////////
    
    std::lock_guard<std::mutex> _(MUTEX);
    //
    auto it = std::find(thread_id.begin(), thread_id.end(), this_id);
    if (it == thread_id.end())
    {
        // видимо глюк элемента в векторе нет
    }
    else
    {
        //тут удаляем элемент из вектора
        auto index = std::distance(thread_id.begin(), it);
        thread_id.erase(thread_id.begin()+index);
    }
 
        //уменьшаем счетчик потоков
        --thread_count;
        cv.notify_all();
        //cv.notify_one();
 
        std::cout << "thread " << p << "__ID__" << this_id << "And Hndl _" << "" << "\n";
}
 
int main()
{
 
    
    thread tt[N];
    typedef std::chrono::steady_clock Clock;
 
    
    //Запускаем потоки в цикле
    for (int i = 0; i < N; i++)
    {
        cout << "Message from main Start_" << i << "\n" << endl;
        //передаем в поток переменную
        tt[i] = thread(&f1, (void*)i);
        
        //получаем Id потока и выводим на экран
        tt[i].get_id();
        cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() <<" And ID is __" << tt[i].get_id() <<" \n";
    
        //  tt[i].detach();
    }
 
    //Работаем с таймером
    auto t0 = Clock::now();
    auto t1 = t0 + std::chrono::seconds(SecPause);
    
    std::unique_lock<std::mutex> lk(MUTEX);
    
    //Если количество потоков равно нулю, то таймер выключаем, если больше нуля,
    //ждем количество секунд заданное ранее
    {
            while (!time_to_quit && Clock::now() < t1)
            {
                if (thread_count > 0)
                {
                    std::cout << "The Nmbr of Threads running is _"<<thread_count<<endl;
                    cv.wait_until(lk, t1);
                }
                else 
                {
                    break; 
                    //return 0;
                }
            }
 
    }
    
    
    //Посылаем сигнал во все потоки
    time_to_quit = true;
    lk.unlock();
 
    //выводим на экран оповещалку
    std::cout << "Time Out ending HERE\n";
    std::cout << "TRY TO FIN FIN\n";
    
    
 
 
 
    //Работаем со всеми запущенными потоками по схеме:
    //Если в векторе есть не удаленный элемент, значит поток завис, убиваем его, иначе закрываемся корректно.
    for (int i = 0; i < N; i++)
        
    {
        
        std::lock_guard<std::mutex> _(MUTEX);
        if (std::find(thread_id.begin(), thread_id.end(), tt[i].get_id()) != thread_id.end())
        {
            /////////Удаляю по системному хэндлу////////////////////////////////////////////////////////////////////////////
            std::cout << "UUps Time is Out\n";
            std::cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() << " will be Terminated \n";
            
            tt[i].detach();
            
            TerminateThread(tt[i].native_handle(), 0);
                        
                    std::cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() << " was Terminated \n";
            
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
        }
        else
        {
    
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            std::cout << "TRY TO FIN CORRECTLY" << i << " \n";
 
            if (tt[i].joinable())
            {
            std::cout << "potok_" << i << " nat hand_" << tt[i].native_handle() << " Try to Join\n";
            tt[i].join();
            std::cout << "potok_" << i << " nat hand_" << tt[i].native_handle() << " Was Joined" << endl;
            }
            
        }
        
    }
 
    return 0;
 
}
0
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
05.11.2016, 01:37  [ТС]
Итак!!!

Господа, я сделал это наконец, любое количество потоков отрабатывается на УРА!!!
Никаких ошибок не ловлю.

Готовый сырец ниже, ОГРОМНАЯ ПРОСЬБА, если кому-то не будет лень, пожалуйста приведите все это к нормальному виду, может быть в класс обернуть это, я все что мог сделал чтоб это работало, а вот с классами и структурами у меня плоховато пока что, увы.

Осталась одна не ясность, мне ужасно не понятна ситуация при которой в коде при закомментированной одной строке все идет на смарку.

Обычный COUT если его закоментить - FATAL ERROR, который не поддается никакому пониманию, ошибка в дебагере подается только в дезассемблированном виде.

Я искренне не понимаю почему так происходит.

По мере решения задачки появлялось куча проблем с вектором, где я только мютексы не пихал все бесполезно было, пришлось помимо них еще булевы закидать.
Но все работает, я чуть ежиков не выродил, но оно работает без ошибок!!!

В общем результат есть, я в целом доволен.
Все работает без проблем. Запускал по 500 потоков более чем 20 раз, ни одной ошибки не вылетело. Все было отлично.

Еще раз просьбы:
1 - Если возможно посмотрите пожалуйста опытным взглядом на суть ошибки которая вылазит если закоментить один единственный COUT

2 - И, пожалуйста, приведите код к красивому виду, конечно оно работает, но не выглядит.

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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#include <mutex>
#include <chrono>
#include <thread>
#include <iostream>
#include <Windows.h>
#include <condition_variable>
 
#include <vector>
#include <algorithm>
#include <iterator>
 
using namespace std;
mutex MUTEX;
 
const int N = 5;    // Количество потоков
int SecPause = 5;   // Устанавливаем таймер, таймаут
 
int time_to_act = 1;// Таймаут чтоб нажать ОК, чтобы понять что поток будет завершен во время
 
int thread_count = 0;
bool time_to_quit = false;
bool vector_busy_thread = false;
bool vector_busy_main = false;
std::condition_variable cv;
 
std::vector<thread::id> thread_id;
 
 
void f1(void* n)
{
    int p = (int)n;
    //тут задаем вводные, чтобы не получилось ситуации при которой время операции дочернего потока получилась больше длины основного
    int pause = 0;
    int counts = 500;
    int PauseMillisec = (SecPause - time_to_act) * 1000;
 
    //Получаем ID потока
    std::thread::id this_id = std::this_thread::get_id();
 
    {
        //      std::lock_guard<std::mutex> _(MUTEX);
        
        //Записываем ID потока в вектор, увеличиваем счетчик потоков
        MUTEX.lock();
        thread_id.push_back(this_id);
        ++thread_count;
        MUTEX.unlock();
    }
 
 
    ///////////////////////////тут делаем что-то///////////////////
    char buffer[100];
    wsprintf(buffer, "%u", p);
    MessageBox(0, buffer, "", 0);
 
 
    if (time_to_quit !=1)
    //Время вышло, нажимать ОК уже поздновато, в цикл не заходим
    //Актуально для большого числа потоков, больше 300 в том случае,
    //если комп уже висит а ОК жамкнуть можно.
    //Но все работает и без дополнительной проверки на ура
    {
    while (true && pause < PauseMillisec)
    {
        pause += counts;
        {
                        std::cout << "thread_"<<p<<"_" << pause << " working\n";
        }
        ///////////////////////////////////////////////////////////
        std::this_thread::sleep_for(std::chrono::milliseconds(counts));
        ///////////////////////////////////////////////////////////
 
        if (time_to_quit)
        {
            break;
 
        }
    }
 
}
    ///////////////////////////тут делаем что-то///////////////////
 
 
 
    //Проверка блокировки вектора из главной функции
while (true)
{
 
    if (vector_busy_main != 0);
    {
        //
        MUTEX.lock();
        vector_busy_thread = true;
        MUTEX.unlock();
 
    /////////////////////////////////////////////////////////////////////
    //////Строку нельзя комментить ни в коем случае//////////////////////
        std::cout << "Vecto_B_T --TR " << vector_busy_thread <<endl;
    ////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!////
    ////!!!!Фатальная ошибка программа выплевывается не понимаю!!!!//////
    /////////////////////////////////////////////////////////////////////
 
        
//      std::lock_guard<std::mutex> _(MUTEX);
 
        MUTEX.lock();
//          std::cout << "ThreadError Lock --TR__" <<p<< endl;;
            auto it = std::find(thread_id.begin(), thread_id.end(), this_id);
            if (it == thread_id.end())
            {
            // видимо глюк элемента в векторе нет
            }
            else
            {
            //тут удаляем элемент из вектора
            auto index = std::distance(thread_id.begin(), it);
            thread_id.erase(thread_id.begin() + index);
            }
        MUTEX.unlock();
        
        MUTEX.lock();
        vector_busy_thread = false;
        MUTEX.unlock();
 
        //уменьшаем счетчик потоков
        MUTEX.lock();
            --thread_count;
        MUTEX.unlock();
            break;
    }
 
}
 
    cv.notify_all();
//  std::cout << "thread " << p << "__ID__" << this_id << "And Hndl _" << "" << "\n";
}
 
 
 
int main()
{
 
    
    thread tt[N];
    typedef std::chrono::steady_clock Clock;
 
    //Запускаем потоки в цикле
    for (int i = 0; i < N; i++)
    {
        //передаем в поток переменную
        tt[i] = thread(&f1, (void*)i);
        
        //получаем Id потока и выводим на экран
        tt[i].get_id();
        cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() <<" And ID is __" << tt[i].get_id() <<" \n";
    
        //  tt[i].detach();
    }
 
    //Работаем с таймером
    auto t0 = Clock::now();
    auto t1 = t0 + std::chrono::seconds(SecPause);
    
    std::unique_lock<std::mutex> lk(MUTEX);
 
 
    //Если количество потоков равно нулю, то таймер выключаем, если больше нуля,
    //ждем количество секунд заданное ранее
    {
            while (!time_to_quit && Clock::now() < t1)
            {
                if (thread_count > 0)
                {
//                  std::cout << "The Nmbr of Threads running is _"<<thread_count<<endl;
                    cv.wait_until(lk, t1);
                }
                else 
                {
                    lk.unlock();
                    break; 
 
                }
            }
 
    }
 
//Говорим потокам что время вышло
time_to_quit = true;
 
//До тех пор пока условие не выполнится будем ожидать в цикле и проверять наличие сразрешения на блокировку
while (true)
{
 
        if (vector_busy_thread !=1);
    {
            //Посылаем сигнал во все потоки о том что вектор будет заблокирован
            vector_busy_main = true;
            break;
    }
    
}
 
    //Работаем со всеми запущеными потоками по схеме:
    //Если в векторе есть не удаленный элемент, значит поток завис, убиваем его, иначе закрываемся корректно.
    for (int i = 0; i < N; i++)
        
    {
 
        vector_busy_main = true;
 
        if (std::find(thread_id.begin(), thread_id.end(), tt[i].get_id()) != thread_id.end())
        {
            /////////Удаляю по системному хэндлу////////////////////////////////////////////////////////////////////////////
 
//          std::cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() << " will be Terminated \n";
            
            tt[i].detach();
            TerminateThread(tt[i].native_handle(), 0);
            
            //оповещаемся о том что поток удален
            std::cout << "Potok_" << i << " ID_" << tt[i].get_id() << " was Terminated \n";
 
                    //Чистим вектор
                    //////////////////////////////////////////////////////
                    auto it = std::find(thread_id.begin(), thread_id.end(), tt[i].get_id());
                    if (it == thread_id.end())
                    {
                        // видимо глюк элемента в векторе нет
                    }
                    else
                    {
                        //тут удаляем элемент из вектора
                        
                        auto index = std::distance(thread_id.begin(), it);
                        std::lock_guard<std::mutex> _(MUTEX);
                        thread_id.erase(thread_id.begin() + index);
                                            }
                    //////////////////////////////////////////////////////
                    
        }
        else
        {
            //Закрываем поток нормально  
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
            if (tt[i].joinable())
            {
//          std::cout << "potok_" << i << " nat hand_" << tt[i].native_handle() << " Try to Join\n";
            tt[i].join();
            std::cout << "potok_" << i << " ID_" << tt[i].get_id() << " Was Joined" << endl;
            }
            
        }
        
        vector_busy_main = false;
    }
    
    //Чистим вектор, на всякий случай
    thread_id.clear();
    return 0;
 
}
0
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 12:00  [ТС]
Все окончательный вариант, ошибку нашел, никакие COUT больше не нужны.
Добавил еще пару флагов для проверки, пару переменных сделал atomic.
Запускал от 300 до 1000 потоков, с 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
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#define _SCL_SECURE_NO_WARNINGS 
#define D_SCL_SECURE_NO_WARNINGS        
#define _CRT_SECURE_NO_WARNINGS         
 
#include <mutex>
#include <chrono>
#include <thread>
#include <iostream>
#include <Windows.h>
#include <condition_variable>
 
#include <vector>
#include <algorithm>
#include <iterator>
#include <atomic>
 
 
 
using namespace std;
mutex MUTEX;
 
const int N = 500;    // Количество потоков
int SecPause = 15;   // Устанавливаем таймер, таймаут
 
int time_to_act = 5; // Таймаут чтоб нажать ОК, чтобы понять что поток будет завершен во время
 
int thread_count = 0;
atomic<bool> time_to_quit = false;
atomic<bool> vector_busy_thread = false;
atomic<bool> vector_busy_main = false;
 
std::condition_variable cv;
 
std::vector<thread::id> thread_id;
 
 
void f1(void* n)
{
    int p = (int)n;
    //тут задаем вводные, чтобы не получилось ситуации при которой время операции дочернего потока получилась больше длины основного
    int pause = 0;
    int counts = 500;
    int PauseMillisec = (SecPause - time_to_act) * 1000;
 
    //Получаем ID потока
    std::thread::id this_id = std::this_thread::get_id();
 
    {
        //      std::lock_guard<std::mutex> _(MUTEX);
 
        //Записываем ID потока в вектор, увеличиваем счетчик потоков
        MUTEX.lock();
        thread_id.push_back(this_id);
        ++thread_count;
        MUTEX.unlock();
    }
 
 
    ///////////////////////////тут делаем что-то///////////////////
    char buffer[100];
    wsprintf(buffer, "%u", p);
    MessageBox(0, buffer, "", 0);
 
 
    if (time_to_quit != 1)
        //Время вышло, нажимать ОК уже поздновато, в цикл не заходим
        //Актуально для большого числа потоков, больше 300 в том случае,
        //если комп уже висит а ОК жамкнуть можно.
        //Но все работает и без дополнительной проверки на ура
    {
        while (true && pause < PauseMillisec)
        {
            pause += counts;
            {
                std::cout << "thread_" << p << "_" << pause << " working\n";
            }
            ///////////////////////////////////////////////////////////
            std::this_thread::sleep_for(std::chrono::milliseconds(counts));
            ///////////////////////////////////////////////////////////
 
            if (time_to_quit)
            {
                break;
 
            }
        }
 
    }
    ///////////////////////////тут делаем что-то///////////////////
 
//  std::cout << "vector_busy_main --TR " << vector_busy_main << endl;
 
    //Проверка блокировки вектора из главной функции
    while (time_to_quit == 0)
    {
        if (vector_busy_main == 0)
        {
//      if  (vector_busy_thread == 0)
        {
            // Локи не нужны булева проверка плюс атомики
//          MUTEX.lock();
            vector_busy_thread = true;
//          MUTEX.unlock();
 
            /////////////////////////////////////////////////////////////////////
//          std::cout << "Vecto_B_T --TR "<<p<<"__" << vector_busy_thread << endl;
            /////////////////////////////////////////////////////////////////////
 
 
            //      std::lock_guard<std::mutex> _(MUTEX);
 
            // На всякий случай мютекс, обращение к вектору
            MUTEX.lock();
            //          std::cout << "ThreadError Lock --TR__" <<p<< endl;;
            auto it = std::find(thread_id.begin(), thread_id.end(), this_id);
            if (it == thread_id.end())
            {
                // видимо глюк элемента в векторе нет
            }
            else
            {
                //тут удаляем элемент из вектора
                auto index = std::distance(thread_id.begin(), it);
                thread_id.erase(thread_id.begin() + index);
            }
            MUTEX.unlock();
 
//          MUTEX.lock();
            vector_busy_thread = false;
//          MUTEX.unlock();
 
            //уменьшаем счетчик потоков
//          MUTEX.lock();
            --thread_count;
//          MUTEX.unlock();
            break;
        }
        
        }
    }
 
    cv.notify_all();
    //  std::cout << "thread " << p << "__ID__" << this_id << "And Hndl _" << "" << "\n";
}
 
 
 
int main()
{
 
 
    thread tt[N];
    typedef std::chrono::steady_clock Clock;
 
    //Запускаем потоки в цикле
    for (int i = 0; i < N; i++)
    {
        //передаем в поток переменную
        tt[i] = thread(&f1, (void*)i);
 
        //получаем Id потока и выводим на экран
        tt[i].get_id();
        cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() << " And ID is __" << tt[i].get_id() << " \n";
 
        //  tt[i].detach();
    }
 
    //Работаем с таймером
    auto t0 = Clock::now();
    auto t1 = t0 + std::chrono::seconds(SecPause);
 
    std::unique_lock<std::mutex> lk(MUTEX);
 
 
    //Если количество потоков равно нулю, то таймер выключаем, если больше нуля,
    //ждем количество секунд заданное ранее
    {
        while (!time_to_quit && Clock::now() < t1)
        {
            if (thread_count > 0)
            {
                //                  std::cout << "The Nmbr of Threads running is _"<<thread_count<<endl;
                cv.wait_until(lk, t1);
            }
            else
            {
                lk.unlock();
                break;
 
            }
        }
 
    }
 
    //Говорим потокам что время вышло
    time_to_quit = true;
 
    //До тех пор пока условие не выполнится будем ожидать в цикле и проверять наличие сразрешения на блокировку
    while (true)
    {
 
        if (vector_busy_thread != 1)
        {
            //Посылаем сигнал во все потоки о том что вектор будет заблокирован
            vector_busy_main = true;
            break;
        }
 
    }
 
    vector_busy_main = true;
    //Работаем со всеми запущеными потоками по схеме:
    //Если в векторе есть не удаленный элемент, значит поток завис, убиваем его, иначе закрываемся корректно.
    for (int i = 0; i < N; i++)
 
    {
        while (true)
        {
            if (vector_busy_thread == 0)
            {
            
 
                if (std::find(thread_id.begin(), thread_id.end(), tt[i].get_id()) != thread_id.end())
                {
                    /////////Удаляю по системному хэндлу////////////////////////////////////////////////////////////////////////////
 
                    //          std::cout << "Potok_" << i << " nat hand_" << tt[i].native_handle() << " will be Terminated \n";
 
                    tt[i].detach();
                    TerminateThread(tt[i].native_handle(), 0);
 
                    //оповещаемся о том что поток удален
                    std::cout << "Potok_" << i << " ID_" << tt[i].get_id() << " was Terminated \n";
 
                    //Чистим вектор
                    //////////////////////////////////////////////////////
                    auto it = std::find(thread_id.begin(), thread_id.end(), tt[i].get_id());
                    if (it == thread_id.end())
                    {
                        // видимо глюк элемента в векторе нет
                    }
                    else
                    {
                        //тут удаляем элемент из вектора
 
                        auto index = std::distance(thread_id.begin(), it);
                        std::lock_guard<std::mutex> _(MUTEX);
                        thread_id.erase(thread_id.begin() + index);
                    }
                    //////////////////////////////////////////////////////
                }
                else
                {
                    //Закрываем поток нормально 
                    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
                    if (tt[i].joinable())
                    {
                        //          std::cout << "potok_" << i << " nat hand_" << tt[i].native_handle() << " Try to Join\n";
                        tt[i].join();
                        std::cout << "potok_" << i << " ID_" << tt[i].get_id() << " Was Joined" << endl;
                    }
                }
            break;
            }
            else { std::this_thread::sleep_for(std::chrono::milliseconds(30)); }
        }
    }
 
    vector_busy_main = false;
    //Чистим вектор, на всякий случай
    thread_id.clear();
    return 0;
 
}
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.11.2016, 16:21
Цитата Сообщение от lostandleft Посмотреть сообщение
Но ведь это пардон маразм, какой же это параллелизм, ожидать завершение одного потока, для того чтобы начать другой.
Помогите разобраться до конца.
Да так оно и есть, перепишите
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
#include <windows.h>
#include <process.h>
#include <iostream>
 
unsigned __stdcall threadFunction(void* Param)
{
    // .. 
    return 0;
}
 
int main()
{
 
    const int N = 150;
    HANDLE h[N];
    for (int i = 0; i < N; i++)
    {
        h[i] = (HANDLE)_beginthreadex(NULL, 0, &threadFunction, (void*)i, 0, NULL);
    }
 
    // Или же лучше через WaitForMultipleObjects()  
    for (int i = 0; i < N; i++)
    {
        WaitForSingleObject(h[i], INFINITE); // вставляем последовательное ожидание и проблемы нет
    }
 
    return 0;
}

Идея использовать TerminateThread()- плохая идея, это грубый способ, в некоторых случаях могут быть проблемы с освобождением ресурсов - утечки.
1
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 20:43  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Да так оно и есть, перепишите
Спасибо за интерес к вопросу, я перепробовал массу вариантов, они все оказались не рабочими. Ваш код не исключение, казалось бы что тут сложного, одна простая задачка.
Но вот как оказалось, майкросовтовские функции не допилены до конца.
Попробуйте запустить код ниже, и нажимать кнопку ОК раз в секунду, через 40-60 нажатий, отпустите и дайте потокам завершаться так, как мы хотели бы это видеть...к удивлению ничего не произойдет, все буде просто висеть.
Все не так просто как может показаться, если Вам не лень запустите и убедитесь самостоятельно, я запускал 5 раз, ни разу программа не завершилась так, как должна была.
Мой вариант, тот что кривой в перемешку с атомиками мутексами и флагами, отрабатывает на ура.
Возможно я не до конца понимаю весь механизм, и гдето сделал массу ошибок, кроме того, у меня все уродлево и не красиво, не оформлено в функции и классы...но оно работает, повторюсь запускал от 500 до 1000 потоков с 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
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
#include <windows.h>
#include <process.h>
#include <iostream>
#include <chrono>
#include <thread>
 
 
const int N = 150;  // Количество потоков
int SecPause = 15;  // Устанавливаем таймер, таймаут
 
int time_to_act = 3;// Время чтоб нажать ок, чотобы понять что поток будет завершен во время
 
 
unsigned __stdcall threadFunction(void* Param)
{
    int p = (int)Param;
    //тут задаем вводные, чтобы не получилось ситуации при которой время операции дочернего потока получилась больше длины основного
    int pause = 0;
    int counts = 500;
    int PauseMillisec = (SecPause - time_to_act) * 1000;
 
    ///////////////////////////тут делаем что-то///////////////////
    char buffer[100];
    wsprintf(buffer, "%u", p);
    MessageBox(0, buffer, "", 0);
 
        //Время вышло, нажимать ОК уже поздновато, в цикл не заходим
        //Актуально для большого числа потоков, больше 300 в том случае,
        //если комп уже висит а ОК жамкнуть можно.
        //Но все работает и без дополнительной проверки на ура
    {
        while (true && pause < PauseMillisec)
        {
            pause += counts;
            {
                std::cout << "thread_" << p << "_" << pause << " working\n";
            }
            ///////////////////////////////////////////////////////////
            std::this_thread::sleep_for(std::chrono::milliseconds(counts));
            ///////////////////////////////////////////////////////////
        }
    }
    return 0;
}
 
int main()
{
 
 
    HANDLE h[N];
    for (int i = 0; i < N; i++)
    {
        h[i] = (HANDLE)_beginthreadex(NULL, 0, &threadFunction, (void*)i, 0, NULL);
    }
 
    // Или же лучше через WaitForMultipleObjects()  
    for (int i = 0; i < N; i++)
    {
        WaitForSingleObject(h[i], (1000*SecPause)); // вставляем последовательное ожидание и проблемы нет
    }
 
    return 0;
}
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
07.11.2016, 20:53
Цитата Сообщение от lostandleft Посмотреть сообщение
Но вот как оказалось, майкросовтовские функции не допилены до конца.
Опиши точно свою задачу.
А то запуск многих сотен потоков, а затем утверждение о том, что WinAPI-функции
"не допилены" - это все выглядит очень странно. У меня все работает, как говорится.
0
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 21:12  [ТС]
В этой функции просто
WaitForSingleObject
в конкретном примере, последняя итерация будет обрабатываться 15 *150 секунд...так или иначе они выполняются последовательно.
Никакой параллельной работы тут нет, и не пахнет.
Пока не отработает первый Wait не начнет работать второй, и так далее. Поэтому программа висит.

В итоге имеем то, что имеем, если запускать через WaitForMultObj от вываливается ошибка, обозначенная в заголовке темы.
В общем вопрос я не смог решить стандартными механизмами...может быть просто не дошел до этого.

Добавлено через 1 минуту
Цитата Сообщение от Убежденный Посмотреть сообщение
У меня все работает, как говорится
Ну запустите пожалуйста мой код, тот который с флагами, и тот который выполнен в стиле предложенном ранее, Вы увидите разницу.
В моем примере все потоки закрываются через таймаут, что и нужно сделать.
Все потоки должны закрыться по таймауту.

Добавлено через 15 минут
Цитата Сообщение от Убежденный Посмотреть сообщение
утверждение о том, что WinAPI-функции
"не допилены"
Это не утверждение, это только мое убеждение.
Утверждение то, что конкретный мелкий пример я реализовать так и не смог, возможно просто не до конца разобрался во всех возможностях. Поэтому пришлось делать велосипед, на нативных потоках, частично спионерен с гугла, и значительно поперепилен мною уже самостоятельно, но все работает, и вроде бы без проблем.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
07.11.2016, 21:23
Цитата Сообщение от lostandleft Посмотреть сообщение
если запускать через WaitForMultObj от вываливается ошибка, обозначенная в заголовке темы.
WinAPI-функции не предназначены для ожидания на большом количестве
объектов одновременно. Максимум 64. Если ты хочешь преодолеть это
ограничение, то нужно или использовать другую технику (например,
счетчик + event), или использовать RegisterWaitForSingleObject, или
переписать свое приложение как-то иначе. Например, под порты
завершения или другие механизмы, у которых таких ограничений нет.
1
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 21:30  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
или
переписать свое приложение как-то иначе
Ну поэтому я как-то иначе и сделал, так на сколько хватило возможностей и знаний. Все работает, проверял.
Почему в мой код никто вникать не хочет...или хотябы запустить чтобы проверить, что все ОК.

Одна критика ...далеко не всегда конструктивная. Хотя стараюсь прислушиваться, спасибо и за неё.
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.11.2016, 21:32
lostandleft,

1. Начнем с того что стоит определится какой инструментарий используете, std или WinApi лучше ограничится чем то одним, я бы предпочел WinApi если нет необходимости в портируемости.

2. Думаю пихать в потоки MessageBox() плохая идея.

3.
Цитата Сообщение от lostandleft Посмотреть сообщение
Попробуйте запустить код ниже, и нажимать кнопку ОК раз в секунду, через 40-60 нажатий, отпустите и дайте потокам завершаться так, как мы хотели бы это видеть...к удивлению ничего не произойдет, все буде просто висеть.
Все не так просто как может показаться, если Вам не лень запустите и убедитесь самостоятельно, я запускал 5 раз, ни разу программа не завершилась так, как должна была.
А что вы хотели увидеть? Как она должна была завершится?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
07.11.2016, 21:38
lostandleft, твой код переусложнен. Лично для меня он почти нечитаемый.
Поэтому я воздержусь от какой-либо критики и т.п. Я просто не могу, глядя на этот код,
сказать, корректен он или нет. Но знаю, что после TerminateThread, например, нет
абсолютно никакой гарантии, что твое приложение будет корректно завершено.

На WinAPI я бы написал как-то так (упрощенно):
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
#include <Windows.h>
#include <process.h>
#include <cstdio>
 
int const g_NumThreads = 100;
 
HANDLE volatile g_hQuitEvent = NULL;
LONG volatile g_Counter = g_NumThreads;
 
//
// Функция потока.
//
unsigned int CALLBACK ThreadProc(PVOID Param)
{
    printf("Thread ID = %lu\r\n", GetCurrentThreadId());
 
    Sleep(4000); // Тут может быть какая-то полезная работа.
 
    //
    // Уменьшаем счетчик потоков. Если 0, то взводим событие.
    //
 
    if (0 == _InterlockedDecrement(&g_Counter)) {
        SetEvent(g_hQuitEvent);
    }
 
    printf("Bye!\r\n");
 
    return 0;
}
 
//
// Точка входа.
//
int main()
{
    HANDLE Handles[g_NumThreads] = {0};
 
    //
    // Создаем сигнальное событие.
    //
 
    g_hQuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
    if (!g_hQuitEvent) {
        printf("[ERROR] CreateEventW failed, err = 0x%.8lx.\r\n", GetLastError());
        goto Finish;
    }
 
    //
    // Запускаем потоки.
    //
 
    for (int i = 0; i < g_NumThreads; ++i)
    {
        Handles[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, (PVOID)i, 0, NULL);
        if (!Handles[i]) {
            printf("_beginthreadex failed.\r\n");
            goto Finish;
        }
    }
 
    //
    // Ждем, пока событие не будет переведено в сигнальное состояние.
    //
    WaitForSingleObject(g_hQuitEvent, INFINITE);
 
Finish:
 
    //
    // Очистка ресурсов.
    //
 
    for (int i = 0; i < g_NumThreads; ++i) {
        if (Handles[i]) {
            WaitForSingleObject(Handles[i], INFINITE);
            CloseHandle(Handles[i]);
        }
    }
 
    if (g_hQuitEvent) {
        CloseHandle(g_hQuitEvent);
    }
 
    return 0;
}
1
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.11.2016, 21:39
4.
Цитата Сообщение от lostandleft Посмотреть сообщение
Этот же код, оформленный в Вашем стиле, предложенном ранее, не отрабатывает:
Ясен фиг что если породил 1000 потоков с месаджбоксами, пока на все 1000 диалогов не закроешь руками оно не завершится.

Кстати если создавать > 1000 потоков, то еще может быть так что и памяти под них не хватать будет.
0
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 21:42  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
MessageBox() плохая идея
Это только образец, имитация зависшей работы одного из потоков, в реальном приложении все будет иначе.
Имитация работает так, на каком то этапе происходит сбой и код не завершается.

Т.е. Если мы ОК не нажимаем, то соответсвенно код не продолжается далее.
Если нажимаем, то код в потоке выполняется далее.
И в том, и в другом случае у нас есть таймаут, мы не можем ждать больше 15 секунд к примеру.

В моем примере, в последнем, в том который работает, так как нужно.
Потоки закрываются по terminate исключительно в аварийном режиме в случае, если код выполнился до конца до того времени как происходит таймаут, то поток закрывается стандартно по Join.

Кстати, на сколько я понял тот же самый WaitForSingleObject, он отрабатывает все тот же вариант Terminate, если уходит таймаут. Другого способа закрыть поток, я так понял, не существует в принципе.

поэтому с технической точки зрения, я вроде бы как поступаю правильно. Если код выполняется за период таймаута, то я закрывают потоки через Join иначе терминирую их.

Цитата Сообщение от Avazart Посмотреть сообщение
А что вы хотели увидеть? Как она должна была завершится?
Совершенно верно, таймаут то вышел для всех запущенных потоков. Нужно завершаться, а не ждать 15 * 150 секунд...долговато это :-)
0
 Аватар для Martein
704 / 109 / 21
Регистрация: 22.06.2014
Сообщений: 241
07.11.2016, 21:43
lostandleft, когда у вас долго что-либо не получается, почитайте наконец мануалы. Древняя, как говно мамонта книга Джеффри Рихтера вам поможет. Вот конкретная глава.
1
2 / 2 / 3
Регистрация: 04.12.2015
Сообщений: 114
07.11.2016, 21:46  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Лично для меня он почти нечитаемый.


Цитата Сообщение от Убежденный Посмотреть сообщение
Я просто не могу, глядя на этот код,
сказать, корректен он или нет.

Ну я же старался комментарии везде писать, как только возможно и переменные обозваны очень и очень вдумчиво, чтобы понятно все было

Цитата Сообщение от Убежденный Посмотреть сообщение
Но знаю, что после TerminateThread, например, нет
абсолютно никакой гарантии, что твое приложение будет корректно завершено.
Я знаю, что гарантии нет, именно поэтому сначала поток отсоединяется, а уже только потом терминируется, было много сломано палок прежде чем я это понял, программа постоянно вылетала в трубу, как Вы и говорите.
И повторюсь это аварийное завершение, в случае если таймер не вышел из счета, никакой терминации нет, все через Join.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.11.2016, 21:46

Exception thrown at 0x77D75BCA (ntdll.dll): 0xC0000005: Access violation reading location 0x0000
Есть задача Есть решение Основное приложение: #include &quot;stdafx.h&quot; #include &lt;stdio.h&gt; #include &lt;conio.h&gt; #include...

Необработанное исключение по адресу 0x0000000077651DA0 (ntdll.dll) в ProjecktExperement2.exe: 0xC0000005: нарушение прав
Необработанное исключение по адресу 0x0000000077651DA0 (ntdll.dll) в ProjecktExperement2.exe: 0xC0000005: нарушение прав доступа при чтении...

CreateThread или beginthreadex
Как-то так повелось что при создании потока я использую ф-цию CreateThread. Тем не менее, все почему-то советуют пользоваться...

Ошибка ntdll.dll
Всем привет! У меня Macbook Pro Retina 13' 2015 (128gb) и у меня проблема с запуском игры на нем. Установил Windows 8.1 через Bootcamp,...

Wine - Ошибка ntdll.dll
Приветствую товарищи! Обращаюсь к вам с проблемой. Поставил я вайн на убунту и хочу юзать http://www.rstat.ru/RetailStat_2.4.zip...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
Генератор паролей (вариант №2)
Maks 30.10.2026
Обновленная версия ранее созданной обработки. Добавлены следующие реквизиты типа Булево: - Буквы; - Цифры; - Символы. Изменена логика команды "Сгенерировать" и процедуры "ПриОткрытии":. . .
Генератор паролей (вариант №1)
Maks 29.10.2026
Реализация из решения ниже выполнена исключительно по моей инициативе, дабы облегчить себе работу в создании паролей для администрируемых мною сервисов и пользователей. Самым главным критерием для. . .
Установка ChatGPT (Codex) на Windows без использования Microsoft Store
Fabien159 28.10.2026
Здравствуйте всем читающим! Опишу процесс установки ChatGPT (Codex) на Windows, если по каким-то причинам у вас не получается устанавить его через Microsoft Store. И так: 1. Скачиваем с. . .
Программное добавление префикса в нумерацию документов
Maks 27.10.2026
Реализация из решения ниже выполнена в самописной конфигурации на БСП (помощь начинающему коллеге). Задача: Программно добавить префикс в нумерацию документов. Решение: В модуле объекта. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru