Поток не останавливается при использовании WaitForSingleObject()
Следующий код принимает кнопки от 0 до 9 и в зависимости от нажатой кнопки добавляет к глобальной переменной от 1 до 9 (при нажатии соответствующей кнопки) или вычитает 5 при нажатии на 0. Прибавление реализовано в функции ThreadProc1, вычитание в ThreadProc2. При каждом нажатии на кнопку создаётся поток, производит вычисления и записывает результаты в журнал. Последние два значения в журнале - результат работы в "дочернем" потоке и результат работы в основном потоке. Я хотел синхронизировать выполнение потоков с использованием "ручного" события, но WaitForSingleObject почему то не задерживает поток.
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <time.h>
using namespace std;
HANDLE hThread; // дескриптор создаваемого потока
HANDLE hEvent;
DWORD IDThread; // идентификатор потока
LPTHREAD_START_ROUTINE ThreadProc1(struct log1* p);
LPTHREAD_START_ROUTINE ThreadProc2(struct log1* p);
int F = 0; // разделяемая глобальная переменная
clock_t wtime = 200; // время задержки (мс)
void waiting(clock_t dt); // функция задержки
// Журнал
struct log1 {
int nom; // порядковый номер операции
int key; // код нажатой клавиши
DWORD ID; // идентификатор созданного потока
clock_t t1; // время начала операции
clock_t t2; // время завершения операции
clock_t t3; // время входа в критический участок
int F; // результат операции в дочернем потоке
int Fc; // результат операции главном потоке
} mylog[1000];
//=================================================
int main() // главный поток
{
int i = 0; // счетчик операций
int j = 1; // счетчик вывода строк журнала
int key = 1; // код нажатой клавиши
int flag = 1; // признак завершения программы
int Fcontr; // переменная-дублер
mylog[1].t2 = 0; // признак того, что поток не завершен
mylog[1].t3 = 0;
Fcontr = F;
hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); //создание события с ручным режим переключения состояния
if (hEvent == NULL) //если событие не создано вывести ошибку
{
cout << "Ошибка создания события.\n";
return 0;
}
// повторять пока flag !=0 или i<1000
while (flag || i >= 1000)
{
//Прием кода нажатой клавиши
if (_kbhit() != 0)
{
key = _getch();
// формирование переменной-дублера
if (key < 58 || key > 48) Fcontr = Fcontr + key - 48;
if (key == 48) Fcontr = Fcontr - 5;
//Проверка кода нажатой клавиши
switch (key)
{
case 27: {flag = 0; break; } // признак выхода из
// программы (Esc)
case 48: // нажата клавиша "0"
{
i = ++i; //следующая операция
// формируем строку журнала
mylog[i].nom = i;
mylog[i].key = key;
mylog[i].t2 = 0;
mylog[i].t3 = 0;
mylog[i].F = 0;
mylog[i].Fc = Fcontr;
mylog[i].t1 = clock();
// создание потока без немедленного запуска
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, &mylog[i], CREATE_SUSPENDED, &IDThread);
if (hThread == NULL)
{
cout << "Thread error" << key << endl;
_getch();
return 0;
}
else
{
// запуск потока
mylog[i].ID = IDThread;
ResumeThread(hThread);
}
break;
}
case 50: // нажата клавиша "2"
case 51: // нажата клавиша "3"
case 52: // нажата клавиша "4"
case 53: // нажата клавиша "5"
case 54: // нажата клавиша "6"
case 55: // нажата клавиша "7"
case 56: // нажата клавиша "8"
case 57: // нажата клавиша "9"
case 49: // нажата клавиша "1"
{
i = ++i; //следующая операция
// формируем строку журнала
mylog[i].nom = i;
mylog[i].key = key;
mylog[i].t2 = 0;
mylog[i].t3 = 0;
mylog[i].F = 0;
mylog[i].Fc = Fcontr;
mylog[i].t1 = clock();
// создание потока без немедленного запуска
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, &mylog[i], CREATE_SUSPENDED, &IDThread);
if (hThread == NULL)
{
cout << "Thread error" << key << endl;
_getch();
return 0;
}
else
{
// запуск потока
mylog[i].ID = IDThread;
ResumeThread(hThread); //ожидание завершения события
}
}
}
}
// завершение работы потока проверяется по
// сформированному в функции
// потока значению времени t2
if (mylog[j].t2 && mylog[j].t3 != 0)
{
// вывод j-й строки журнала
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[i].t3 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc << endl;
j = ++j; // следующая строка журнала
}
} // повторять пока flag !=0 или i<1000
_getch();
return 0;
}
// функция потока: имитация "чтения", корректировки
// и "записи" разделяемой переменной F
// параметр - указатель на текущую строку журнала
LPTHREAD_START_ROUTINE ThreadProc1(struct log1* p)
{
int Fbuf;
// чтение разделяемой переменной в буферную переменную
(*p).t3 = clock();
WaitForSingleObject(hEvent, INFINITE);
ResetEvent(hEvent);
Fbuf = F;
waiting(wtime); // задержка
// корректировка буферной переменной
if ((*p).key < 58 || (*p).key > 48) Fbuf = Fbuf + (*p).key - 48;
waiting(wtime); // задержка
// запись из буферной переменной в разделяемую переменную
F = Fbuf;
SetEvent(hEvent); //конец критического учатка, сброс состояния события
// запись результата в текущую строку журнала
(*p).F = F;
(*p).t2 = clock(); // время окончания работы потока
return 0;
}
LPTHREAD_START_ROUTINE ThreadProc2(struct log1* p)
{
int Fbuf;
(*p).t3 = clock();
WaitForSingleObject(hEvent, INFINITE);
ResetEvent(hEvent); //вход в критический участок, событие отмечается
Fbuf = F;
waiting(wtime);
if ((*p).key == 48) Fbuf = Fbuf - 5;
waiting(wtime);
F = Fbuf;
SetEvent(hEvent); //конец критического участка, сброс состояния события
(*p).F = F;
(*p).t2 = clock();
return 0;
}
// функция задержки
// параметр - время задержки в мс
void waiting(clock_t dt) {
clock_t tn;
tn = clock();
while (clock() - tn < dt);
return;
}