multithreading - 加入 DLL_DETACH 中的线程
问题描述
我有一个注入进程的 DLL,当进程终止时,我希望线程在 DLL 卸载时终止。
因此,我想出了以下内容:
// Wrapper around std::thread that notifies the task it should stop..
class TaskThread {
private:
std::mutex mutex;
std::thread thread;
std::atomic_bool stop;
std::function<void()> onStop;
public:
TaskThread(std::function<void(TaskThread*)> &&task, std::function<void()> &&onStop);
~TaskThread();
bool stopped();
};
TaskThread::TaskThread(std::function<void(TaskThread*)> &&task, std::function<void()> &&onStop) : onStop(onStop)
{
this->thread = std::thread([this, task]{
task(this);
});
}
TaskThread::~TaskThread()
{
//set stop to true..
std::unique_lock<std::mutex> lock(this->mutex);
this->stop = true;
lock.unlock();
//signal the task
onStop();
//join the thread..
this->thread.join();
}
bool TaskThread::stopped()
{
std::unique_lock<std::mutex> lock(this->mutex);
bool stopped = this->stop;
lock.unlock();
return stopped;
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
static std::unique_ptr<TaskThread> task_thread;
static std::unique_ptr<Semaphore> semaphore;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hinstDLL);
semaphore.reset(new Semaphore(0));
task_thread.reset(new TaskThread([&](TaskThread* thread){
while(thread && !thread->stopped()) {
if (!semaphore)
{
return;
}
semaphore->wait();
if (!thread || thread->stopped())
{
return;
}
runTask(); //execute some function
}
}, [&]{
if (semaphore)
{
semaphore->signal();
}
}));
}
break;
case DLL_PROCESS_DETACH:
{
task_thread.reset(); //delete the thread.. triggering the destructor
}
break;
}
return TRUE;
}
但是,这将导致我的程序在我退出时挂起。我必须通过任务管理器将其杀死。如果我分离线程,一切都会正常工作并干净地退出(无论我是在创建线程之后还是在析构函数中分离线程都没有关系)。
那么为什么当我加入线程时进程挂起?
解决方案
调用时会持有锁DllMain()
,因此等待线程退出最终会递归调用DllMain()
( THREAD_DETACH
and PROCESS_DETACH
) 并挂在该锁上。
进一步阅读:动态链接库最佳实践
推荐阅读
- powershell - 运行 ForEach-Object -Parallel,导出数据丢失
- python - 在电子邮件开始之前获取所有电子邮件和单词
- python - 我的代码返回一个空列表我该如何解决?
- jenkins - 访问 Conducto Exec 节点的标准输出
- c# - 更改可编辑组合框中可编辑文本框的属性
- javascript - 错误:网络错误:url_1.URL 不是 new ApolloError 的构造函数
- android - 容器只改变高度
- sql-server - SQL 使用 sp_OAGetProperty 获取视频尺寸
- reactjs - 在 react 中添加一个对象到 useState。错误“重新渲染过多”
- r - 记住:eval(XXX_parsed) 比 eval(parse(text = XXX)) 快得多