Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 终止工作线程和主线程之间的争用条件_C++_Multithreading_Threadpool_Deadlock_Race Condition - Fatal编程技术网

C++ 终止工作线程和主线程之间的争用条件

C++ 终止工作线程和主线程之间的争用条件,c++,multithreading,threadpool,deadlock,race-condition,C++,Multithreading,Threadpool,Deadlock,Race Condition,我在从主线程终止工作线程时遇到问题。到目前为止,我尝试的每种方法要么导致竞争条件,要么导致死锁 工作线程存储在名为ThreadPool的类中的内部类中,ThreadPool使用unique_ptr维护这些工作线程的向量 以下是我的线程池的标题: class ThreadPool { public: typedef void (*pFunc)(const wpath&, const Args&, Global::mFile_t&, std::mutex&, std:

我在从主线程终止工作线程时遇到问题。到目前为止,我尝试的每种方法要么导致竞争条件,要么导致死锁

工作线程存储在名为ThreadPool的类中的内部类中,ThreadPool使用unique_ptr维护这些工作线程的向量

以下是我的线程池的标题:

class ThreadPool
{
public:
typedef void (*pFunc)(const wpath&, const Args&, Global::mFile_t&, std::mutex&, std::mutex&);       // function to point to
private:

    class WorkerThread
    {
    private:
        ThreadPool* const _thisPool;        // reference enclosing class

        // pointers to arguments
        wpath _pPath;               // member argument that will be modifyable to running thread
        Args * _pArgs;
        Global::mFile_t * _pMap;

        // flags for thread management
        bool _terminate;                    // terminate thread
        bool _busy;                         // is thread busy?
        bool _isRunning;

        // thread management members

        std::mutex              _threadMtx;
        std::condition_variable _threadCond;
        std::thread             _thisThread;

        // exception ptr
        std::exception_ptr _ex;

        // private copy constructor
        WorkerThread(const WorkerThread&): _thisPool(nullptr) {}
    public:
        WorkerThread(ThreadPool&, Args&, Global::mFile_t&);
        ~WorkerThread();

        void setPath(const wpath);          // sets a new task
        void terminate();                   // calls terminate on thread
        bool busy() const;                  // returns whether thread is busy doing task
        bool isRunning() const;             // returns whether thread is still running
        void join();                        // thread join wrapper
        std::exception_ptr exception() const;

        // actual worker thread running tasks
        void thisWorkerThread();
    };

    // thread specific information
    DWORD _numProcs;                        // number of processors on system
    unsigned _numThreads;                   // number of viable threads
    std::vector<std::unique_ptr<WorkerThread>> _vThreads;   // stores thread pointers - workaround for no move constructor in WorkerThread
    pFunc _task;                            // the task threads will call

    // synchronization members
    unsigned _barrierLimit;                 // limit before barrier goes down
    std::mutex _barrierMtx;                 // mutex for barrier
    std::condition_variable _barrierCond;   // condition for barrier
    std::mutex _coutMtx;

public:
    // argument mutex
    std::mutex matchesMap_mtx;
    std::mutex coutMatch_mtx;

    ThreadPool(pFunc f);

    // wake a thread and pass it a new parameter to work on
    void callThread(const wpath&);

    // barrier synchronization
    void synchronizeStartingThreads();

    // starts and synchronizes all threads in a sleep state
    void startThreads(Args&, Global::mFile_t&);

    // terminate threads
    void terminateThreads();

private:
};
实际的线程循环

void ThreadPool::WorkerThread::thisWorkerThread()
{
    _thisPool->synchronizeStartingThreads();

    try
    {
        while (!_terminate)
        {
            {
                _thisPool->_coutMtx.lock();
                std::cout << std::this_thread::get_id() << " Sleeping..." << std::endl;
                _thisPool->_coutMtx.unlock();
                _busy = false;
                std::unique_lock<std::mutex> lock(_threadMtx);
                _threadCond.wait(lock);
            }
            _thisPool->_coutMtx.lock();
            std::cout << std::this_thread::get_id() << " Awake..." << std::endl;
            _thisPool->_coutMtx.unlock();
            if(_terminate)
                break;

            _thisPool->_task(_pPath, *_pArgs, *_pMap, _thisPool->coutMatch_mtx, _thisPool->matchesMap_mtx);

            _thisPool->_coutMtx.lock();
            std::cout << std::this_thread::get_id() << " Finished Task..." << std::endl;
            _thisPool->_coutMtx.unlock();

        }
        _thisPool->_coutMtx.lock();
        std::cout << std::this_thread::get_id() << " Terminating" << std::endl;
        _thisPool->_coutMtx.unlock();   
    }
    catch (const std::exception&)
    {
        _ex = std::current_exception();
    }
    _isRunning = false;
}
void ThreadPool::WorkerThread::thisWorkerThread()
{
_此池->同步启动读取();
尝试
{
而(!\u终止)
{
{
_thisPool->_coutMtx.lock();
标准::cout matchemap_mtx);
_thisPool->_coutMtx.lock();
std::cout get()->_thisThread.detach();
//若线程抛出异常,则在main中重新抛出它
if(it->get()->exception()!=nullptr)
std::rethrow_异常(it->get()->exception());
}
}
最后是调用线程池的函数(scan函数在main上运行)

//递归扫描路径以查找所选扩展类型的所有文件,调用线程来解析文件
unsigned int Functions::Scan(wpath路径、常量Args和Args、线程池和池)
{
wre草书目录迭代器d(路径),e;
未签名的整数filesFound=0;
while(d!=e)
{
if(args.verbose())
std::wcout path());
}
}
++d;
}

std::cout我不理解线程终止和连接的问题

加入线程就是等待给定的线程终止,因此这正是您想要做的。如果线程已经完成执行,
join
将立即返回

因此,您只需要在
终止
调用期间加入每个线程,就像您在代码中所做的那样

注意:当前,如果刚终止的线程有活动的
异常,\u ptr
,您将立即重新引发任何异常。这可能会导致未连接的线程。在处理这些异常时,您必须记住这一点


更新:查看代码后,我看到一个潜在的错误:
std::condition\u variable::wait()
在发生虚假唤醒时可以返回。如果是这种情况,您将在上次工作的路径上再次工作,导致错误的结果。您应该为新工作设置一个标志,该标志在添加新工作时设置,并且
\u threadCond.wait(锁定)
行应该在一个循环中,用于检查标志和
\u terminate
。但不确定该循环是否能解决您的问题。

问题有两个方面:

synchronizeStartingThreads()有时会阻塞1或2个线程,等待OK(while(某些条件)barrierCond.wait(锁定)中的一个问题)。该条件有时不会计算为true。删除while循环修复了此阻塞问题

第二个问题是工作线程可能会进入_threadMtx,并且在进入_threadCond.wait()之前调用了notify_all,因为已经调用了notify,线程将永远等待


上述代码只在20%的时间内有效。每隔一段时间,当我有连接时,程序会无限期挂起。如果我删除连接,则不会出现死锁,但main会在线程之前终止。连接以某种方式导致死锁。是否可能是两个或多个线程之间解除锁定?它们是否共享变量es?如果是这样的话,删除
join
调用只是在主线程终止时通过杀死子线程来隐藏死锁。是的。所有工作线程共享一个主变量-映射的映射。我正在通过函数指针传递一个互斥锁,以锁定映射中元素的插入。但是,它现在是耳朵什么也不做,因为地图有时仍然返回错误的数据。除了点->程序经过这一点,所以地图已经填充,文件已经扫描了。只有在我调用terminateThreads()时它是否会无限期地挂起。因此,当我的线程此时都处于睡眠状态时,我看不到任何死锁。你不能在线程的主循环中使用bool,并希望在线程中观察到将其设置为true。需要使用std::atomic。这不是唯一的问题,工作线程可能会被阻塞,并且永远不会观察退出请求。一般来说,这是一个很难解决的问题,这是C++11添加的原因。
void ThreadPool::WorkerThread::thisWorkerThread()
{
    _thisPool->synchronizeStartingThreads();

    try
    {
        while (!_terminate)
        {
            {
                _thisPool->_coutMtx.lock();
                std::cout << std::this_thread::get_id() << " Sleeping..." << std::endl;
                _thisPool->_coutMtx.unlock();
                _busy = false;
                std::unique_lock<std::mutex> lock(_threadMtx);
                _threadCond.wait(lock);
            }
            _thisPool->_coutMtx.lock();
            std::cout << std::this_thread::get_id() << " Awake..." << std::endl;
            _thisPool->_coutMtx.unlock();
            if(_terminate)
                break;

            _thisPool->_task(_pPath, *_pArgs, *_pMap, _thisPool->coutMatch_mtx, _thisPool->matchesMap_mtx);

            _thisPool->_coutMtx.lock();
            std::cout << std::this_thread::get_id() << " Finished Task..." << std::endl;
            _thisPool->_coutMtx.unlock();

        }
        _thisPool->_coutMtx.lock();
        std::cout << std::this_thread::get_id() << " Terminating" << std::endl;
        _thisPool->_coutMtx.unlock();   
    }
    catch (const std::exception&)
    {
        _ex = std::current_exception();
    }
    _isRunning = false;
}
void ThreadPool::terminateThreads()
{
    for (std::vector<std::unique_ptr<WorkerThread>>::iterator it = _vThreads.begin(); it != _vThreads.end(); ++it)
    {
        it->get()->terminate();
        //it->get()->_thisThread.detach();

        // if thread threw an exception, rethrow it in main
        if (it->get()->exception() != nullptr)
            std::rethrow_exception(it->get()->exception());
    }
}
// scans a path recursively for all files of selected extension type, calls thread to parse file
unsigned int Functions::Scan(wpath path, const Args& args, ThreadPool& pool)
{
    wrecursive_directory_iterator d(path), e;
    unsigned int filesFound = 0;
    while ( d != e )
    {
        if (args.verbose())
            std::wcout << L"Grepping: " << d->path().string() << std::endl;

        for (Args::ext_T::const_iterator it = args.extension().cbegin(); it != args.extension().cend(); ++it)
        {
            if (extension(d->path()) == *it)
            {
                ++filesFound;
                pool.callThread(d->path());
            }
        }
        ++d;
    }

    std::cout << "Scan Function: Calling TerminateThreads() " << std::endl;
    pool.terminateThreads();
    std::cout << "Scan Function: Called TerminateThreads() " << std::endl;
    return filesFound;
}
{
    // terminate() is called
    std::unique_lock<std::mutex> lock(_threadMtx);
    // _threadCond.notify_all() is called here
    _busy = false;
    _threadCond.wait(lock);
    // thread is blocked forever
}
_threadCond.wait_for(lock, std::chrono::milliseconds(30));  // hold the lock a max of 30ms

// after the lock, and the termination check

if(_busy)
        {
            Global::mFile_t rMap = _thisPool->_task(_pPath, *_pArgs, _thisPool->coutMatch_mtx);
            _workerMap.element.insert(rMap.element.begin(), rMap.element.end());
        }