互斥体上的 C++ 并发段错误
C++ Concurrency segfault on mutex
你好,
我是 C++ 的新手,但我有 6 年 Java 经验,2 年 C 经验和一些并发基础知识。我正在尝试创建一个线程池来处理任务。它在下面与相关的测试主。
似乎错误是由
产生的
void ThreadPool::ThreadHandler::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(queueMutex);
正如我的调试器所说,但是在进行传统的 cout 调试时,我发现有时它可以在没有段错误和删除
的情况下工作
threads.emplace(handler->getSize(), handler);
来自 ThreadPool::enqueueTask()
大大提高了稳定性。
总的来说,我认为这也与我对condition_variable(称为闲人)的使用不当有关。
编译器:CLion 中的 minGW-w64
.cpp
#include <iostream>
#include "ThreadPool.h"
ThreadPool::ThreadHandler::ThreadHandler(ThreadPool *parent) : parent(parent) {
thread = std::thread([&]{
while (this->parent->alive){
if (getSize()){
std::lock_guard<std::mutex> lock(queueMutex);
(*(queue.front()))();
queue.pop_front();
} else {
std::unique_lock<std::mutex> lock(idlerMutex);
idler.wait(lock);
}
}
});
}
void ThreadPool::ThreadHandler::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(queueMutex);
queue.push_back(task);
idler.notify_all();
}
size_t ThreadPool::ThreadHandler::getSize() {
std::lock_guard<std::mutex> lock(queueMutex);
return queue.size();
}
void ThreadPool::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(threadsMutex);
std::map<int, ThreadHandler*>::iterator iter = threads.begin();
threads.erase(iter);
ThreadHandler *handler = iter->second;
handler->enqueueTask(task);
threads.emplace(handler->getSize(), handler);
}
ThreadPool::ThreadPool(size_t size) {
for (size_t i = 0; i < size; ++i) {
std::lock_guard<std::mutex> lock(threadsMutex);
ThreadHandler *handler = new ThreadHandler(this);
threads.emplace(handler->getSize(), handler);
}
}
ThreadPool::~ThreadPool() {
std::lock_guard<std::mutex> lock(threadsMutex);
auto it = threads.begin(), end = threads.end();
for (; it != end; ++it) {
delete it->second;
}
}
.h
#ifndef WLIB_THREADPOOL_H
#define WLIB_THREADPOOL_H
#include <mutex>
#include <thread>
#include <list>
#include <map>
#include <condition_variable>
class ThreadPool {
private:
class ThreadHandler {
std::condition_variable idler;
std::mutex idlerMutex;
std::mutex queueMutex;
std::thread thread;
std::list<void (*)(void)> queue;
ThreadPool *parent;
public:
ThreadHandler(ThreadPool *parent);
void enqueueTask(void (*task)(void));
size_t getSize();
};
std::multimap<int, ThreadHandler*> threads;
std::mutex threadsMutex;
public:
bool alive = true;
ThreadPool(size_t size);
~ThreadPool();
virtual void enqueueTask(void (*task)(void));
};
#endif //WLIB_THREADPOOL_H
主要内容:
#include <iostream>
#include <ThreadPool.h>
ThreadPool pool(3);
void fn() {
std::cout << std::this_thread::get_id() << '\n';
pool.enqueueTask(fn);
};
int main() {
std::cout << "Hello, World!" << std::endl;
pool.enqueueTask(fn);
return 0;
}
您的 main()
函数调用 enqueueTask()
.
紧接着,您的 main()
returns.
这让齿轮开始运转以结束您的过程。这涉及调用所有全局对象的析构函数。
ThreadPool
的析构函数然后继续删除所有动态作用域的线程。
线程还在运行。随之而来的是欢闹。
您需要实现所有线程有序关闭的过程。
意思是把active
设置为false,把所有的线都踢到小腿上,然后加入所有的线,顺其自然,最后毁灭一切。
P.S。 -- 您需要修复 alive
的检查方式。您还需要使对 alive
的访问成为线程安全的,并受互斥体保护。问题是线程可能持有两个不同互斥量之一的锁。这使得这个过程有些复杂。此处需要进行一些重新设计。
你好,
我是 C++ 的新手,但我有 6 年 Java 经验,2 年 C 经验和一些并发基础知识。我正在尝试创建一个线程池来处理任务。它在下面与相关的测试主。
似乎错误是由
产生的void ThreadPool::ThreadHandler::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(queueMutex);
正如我的调试器所说,但是在进行传统的 cout 调试时,我发现有时它可以在没有段错误和删除
的情况下工作threads.emplace(handler->getSize(), handler);
来自 ThreadPool::enqueueTask()
大大提高了稳定性。
总的来说,我认为这也与我对condition_variable(称为闲人)的使用不当有关。
编译器:CLion 中的 minGW-w64
.cpp
#include <iostream>
#include "ThreadPool.h"
ThreadPool::ThreadHandler::ThreadHandler(ThreadPool *parent) : parent(parent) {
thread = std::thread([&]{
while (this->parent->alive){
if (getSize()){
std::lock_guard<std::mutex> lock(queueMutex);
(*(queue.front()))();
queue.pop_front();
} else {
std::unique_lock<std::mutex> lock(idlerMutex);
idler.wait(lock);
}
}
});
}
void ThreadPool::ThreadHandler::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(queueMutex);
queue.push_back(task);
idler.notify_all();
}
size_t ThreadPool::ThreadHandler::getSize() {
std::lock_guard<std::mutex> lock(queueMutex);
return queue.size();
}
void ThreadPool::enqueueTask(void (*task)(void)) {
std::lock_guard<std::mutex> lock(threadsMutex);
std::map<int, ThreadHandler*>::iterator iter = threads.begin();
threads.erase(iter);
ThreadHandler *handler = iter->second;
handler->enqueueTask(task);
threads.emplace(handler->getSize(), handler);
}
ThreadPool::ThreadPool(size_t size) {
for (size_t i = 0; i < size; ++i) {
std::lock_guard<std::mutex> lock(threadsMutex);
ThreadHandler *handler = new ThreadHandler(this);
threads.emplace(handler->getSize(), handler);
}
}
ThreadPool::~ThreadPool() {
std::lock_guard<std::mutex> lock(threadsMutex);
auto it = threads.begin(), end = threads.end();
for (; it != end; ++it) {
delete it->second;
}
}
.h
#ifndef WLIB_THREADPOOL_H
#define WLIB_THREADPOOL_H
#include <mutex>
#include <thread>
#include <list>
#include <map>
#include <condition_variable>
class ThreadPool {
private:
class ThreadHandler {
std::condition_variable idler;
std::mutex idlerMutex;
std::mutex queueMutex;
std::thread thread;
std::list<void (*)(void)> queue;
ThreadPool *parent;
public:
ThreadHandler(ThreadPool *parent);
void enqueueTask(void (*task)(void));
size_t getSize();
};
std::multimap<int, ThreadHandler*> threads;
std::mutex threadsMutex;
public:
bool alive = true;
ThreadPool(size_t size);
~ThreadPool();
virtual void enqueueTask(void (*task)(void));
};
#endif //WLIB_THREADPOOL_H
主要内容:
#include <iostream>
#include <ThreadPool.h>
ThreadPool pool(3);
void fn() {
std::cout << std::this_thread::get_id() << '\n';
pool.enqueueTask(fn);
};
int main() {
std::cout << "Hello, World!" << std::endl;
pool.enqueueTask(fn);
return 0;
}
您的 main()
函数调用 enqueueTask()
.
紧接着,您的 main()
returns.
这让齿轮开始运转以结束您的过程。这涉及调用所有全局对象的析构函数。
ThreadPool
的析构函数然后继续删除所有动态作用域的线程。
线程还在运行。随之而来的是欢闹。
您需要实现所有线程有序关闭的过程。
意思是把active
设置为false,把所有的线都踢到小腿上,然后加入所有的线,顺其自然,最后毁灭一切。
P.S。 -- 您需要修复 alive
的检查方式。您还需要使对 alive
的访问成为线程安全的,并受互斥体保护。问题是线程可能持有两个不同互斥量之一的锁。这使得这个过程有些复杂。此处需要进行一些重新设计。