Cocket在互斥锁上的并发段错误

Wic*_*par 1 c++ concurrency mutex condition-variable

你好,

我是C++的新手,但我有6年的Java经验,2年的C经验和一些并发基础知识.我正在尝试创建一个线程池来处理任务.它位于相关测试主体的下方.

似乎错误是由...生成的

void ThreadPool::ThreadHandler::enqueueTask(void (*task)(void)) {
    std::lock_guard<std::mutex> lock(queueMutex);
Run Code Online (Sandbox Code Playgroud)

正如我的调试器所说,但是做传统的cout调试,我发现有时候它可以在没有segfaulting和删除的情况下工作

threads.emplace(handler->getSize(), handler);
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

主要:

#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;
}
Run Code Online (Sandbox Code Playgroud)

Sam*_*hik 5

你的main()函数调用enqueueTask().

紧接着,你的main()回报.

这样可以使齿轮运转,从而减少您的过程.这涉及调用所有全局对象的析构函数.

ThreadPool然后,析构函数继续删除所有动态范围的线程.

虽然线程仍在运行.随之而来的是欢闹.

您需要实现有序关闭所有线程的过程.

这意味着设置active为false,踢出小腿中的所有线程,然后加入所有线程,然后让大自然走上正轨,最后摧毁一切.

PS - 您需要修复如何alive检查.您还需要访问alive线程安全,受互斥锁保护.问题是线程可能会锁定两个不同的互斥锁之一.这使得这个过程有点复杂.这里有一些重新设计是有序的.