我想同步自动生成的线程。我写了这样的代码。此代码定期按生成的顺序写入每个线程的名称。
但是当我运行我的代码时,有时候我会得到一个很好的结果,有时候我会遇到这样的错误:所有都挂起(用清晰的黑屏睡觉)。它意外发生。
通过调试,我了解到有时候子线程并不想唤醒。谁能说出来:为什么?我该如何解决这个问题?
我在Windows 10 x64上使用Microsoft Visual Studio 2010 SP1 Professional 我的代码:
的main.cpp
if (csrf_token mismatch) {
return redirect()->back();
}
ThreadFuncs.cpp
#include "ThreadManager.h"
#include "ThreadFuncs.h"
int main() {
ThreadManager mng(2.0, 1.3);
mng.runAll();
Sleep(100000);
return 0;
}
ThreadManager.h
#include <iostream>
#include <string>
#include "Sync.h"
#include "ThreadManager.h"
#include "ThreadFuncs.h"
DWORD WINAPI threadPrinter(LPVOID ptr)
{
ThreadManager* manager = reinterpret_cast<ThreadManager*>(ptr);
if (!manager)
{
return 1;
}
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
while (!manager->isStopPrinting)
{
EnterCriticalSection(&manager->workWithFlags);
for (auto it = manager->flags.begin(); it != manager->flags.end(); ++it)
{
(*it)->operation = OPERATION_START_WRITING_NAME;
WakeConditionVariable(&(*it)->canWork);
SleepConditionVariableCS(&(*it)->isEndWork, &cs, INFINITE);
}
LeaveCriticalSection(&manager->workWithFlags);
Sleep(manager->showInterval * 1000);
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
return 0;
}
DWORD WINAPI threadGenerator(LPVOID ptr)
{
ThreadManager* manager = reinterpret_cast<ThreadManager*>(ptr);
if (!manager)
{
return 1;
}
while (!manager->isStopGeneration)
{
manager->generateNewThread();
Sleep(manager->createNewThreadInterval * 1000);
}
return 0;
}
DWORD WINAPI threadChild(LPVOID ptr)
{
Sync* s = reinterpret_cast<Sync*> (ptr);
if (s == NULL)
{
return 1;
}
std::string name = "Th_" + std::to_string(static_cast<long long>(s->index));
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
while (true)
{
SleepConditionVariableCS(&s->canWork, &cs, INFINITE);
if (s->operation == OPERATION_EXIT_THREAD)
{
break;
}
if (s->operation == OPERATION_START_WRITING_NAME)
{
std::cout << name << " ";
WakeConditionVariable(&s->isEndWork);
continue;
}
WakeConditionVariable(&s->isEndWork);
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
return 0;
}
ThreadManager.cpp
#pragma once
#include <windows.h>
#include <deque>
#include "Sync.h"
#include "ThreadFuncs.h"
class ThreadManager
{
std::deque <Sync *> flags;
CRITICAL_SECTION workWithFlags;
friend DWORD WINAPI threadGenerator(LPVOID);
friend DWORD WINAPI threadPrinter(LPVOID);
HANDLE printerThread;
HANDLE generatorThread;
const double showInterval;
const double createNewThreadInterval;
bool isStopGeneration;
bool isStopPrinting;
public:
ThreadManager(const double& showInterval, const double& createNewThreadInterval);
~ThreadManager();
void generateNewThread();
bool removeThread(); //kill random thread
bool removeThread(int index);
void runAll();
void stopAll();
int getNumOfThreads() const;
};
Sync.h
#include "ThreadManager.h"
ThreadManager::ThreadManager(const double& showInterval, const double& createNewThreadInterval) :
showInterval(showInterval), createNewThreadInterval(createNewThreadInterval), isStopGeneration(true), isStopPrinting(true)
{
InitializeCriticalSection(&workWithFlags);
printerThread = NULL;
generatorThread = NULL;
}
int ThreadManager::getNumOfThreads() const
{
return flags.size();
}
void ThreadManager::runAll()
{
//run generation
isStopGeneration = false;
if (generatorThread != NULL)
{
return;
}
generatorThread = CreateThread(NULL, 0, threadGenerator, this, /*run immediately*/ 0, NULL);
if (generatorThread == NULL)
{
//Stream::log("Error creating generation thread");
isStopGeneration = true;
}
//run printing
isStopPrinting = false;
if (printerThread != NULL)
{
return;
}
printerThread = CreateThread(NULL, 0, threadPrinter, this, /*run immediately*/ 0, NULL);
if (printerThread == NULL)
{
//Stream::log("Error creating printer thread");
isStopPrinting = true;
}
}
void ThreadManager::stopAll()
{
//stop generation
if (!generatorThread)
{
return;
}
isStopGeneration = true;
WaitForSingleObject(generatorThread, INFINITE);
CloseHandle(generatorThread);
generatorThread = NULL;
//stop printing
if (!printerThread)
{
return;
}
isStopPrinting = true;
WaitForSingleObject(printerThread, INFINITE);
CloseHandle(printerThread);
printerThread = NULL;
}
ThreadManager::~ThreadManager()
{
stopAll();
while (!flags.empty())
{
removeThread(flags.size() - 1);
}
DeleteCriticalSection(&workWithFlags);
}
void ThreadManager::generateNewThread()
{
static int newIndex = 0;
Sync* s = new Sync();
s->index = newIndex;
newIndex++;
s->threadHandle = CreateThread(NULL, 0, threadChild, s, /*run immediately*/ 0, NULL);
if (s->threadHandle == NULL)
{
//Stream::log("Error creating new thread");
delete s;
return;
}
EnterCriticalSection(&workWithFlags);
flags.push_back(s);
LeaveCriticalSection(&workWithFlags);
}
bool ThreadManager::removeThread(int index)
{
EnterCriticalSection(&workWithFlags);
if (flags.size() <= index || index < 0)
{
LeaveCriticalSection(&workWithFlags);
return false;
}
Sync* s = flags[index];
flags.erase(flags.begin() + index);
s->operation = OPERATION_EXIT_THREAD;
WakeConditionVariable(&s->canWork);
WaitForSingleObject(s->threadHandle, INFINITE);
delete s;
LeaveCriticalSection(&workWithFlags);
return true;
}
bool ThreadManager::removeThread()
{
EnterCriticalSection(&workWithFlags);
int size = flags.size();
LeaveCriticalSection(&workWithFlags);
if (!size)
{
return false;
}
return removeThread(rand() % size);
}
更新:
答案 0 :(得分:1)
您的threadPrinter()
和threadChild()
函数未正确同步线程。您正在创建一个无用的新本地CRITICAL_SECTION
,因为其他线程无权访问它,因此它实际上并未锁定对任何内容的访问权限。当您应该通过CRITICAL_SECTION
时,您将本地SleepConditionVariableCS()
传递给manager->workWithFlags
。但这样做会引入一个新的逻辑漏洞,因为一旦一个线程解锁workWithFlags
以等待一个条件变量,其他线程就可以自由修改flags
的内容,你在等待的时候没有检查当发出条件变量信号时,线程重新获取workWithFlags
锁。
根据您的尝试,您可能根本不应该使用条件变量。条件变量用于在等待变量发出信号时解锁获取的锁(临界区或超薄读取器/写入器锁),然后在发出信号后再次重新获取该锁。这不是您的代码所需要的。使用可签名事件会更有意义。查看CreateEvent()
,SetEvent()
/ ResetEvent()
和WaitForSingleObject()
。发出事件信号以开始某些工作,并在完成该工作时发出另一个事件的信号。您不需要为此使用条件变量。