【发布时间】:2016-08-27 18:13:15
【问题描述】:
你好,
我对 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(称为 idler)的不当使用有关。
编译器: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;
}
【问题讨论】:
-
你知道你上面的例子永远不会终止吗?该任务总是启动另一个任务。
-
您确定地图
threads永远不会为空吗?为什么不使用std::function作为“功能”? -
@Steve 是的,这是为了测试更长的时间。
-
@JoachimPileborg theads 有时是空的,这就是我检查大小的原因,这有关系吗?对于函数,我比较熟悉C语法。
-
threads.erase(iter);iter 无效,之后您不能(安全地)使用它。尝试:iter = threads.erase(iter);iter 接收一个新的有效迭代器或在使用它调用erase(iter)之前使用它。
标签: c++ concurrency mutex condition-variable