Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.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/6/multithreading/4.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_C++11 - Fatal编程技术网

C++ 处理多线程清理的最佳方法

C++ 处理多线程清理的最佳方法,c++,multithreading,c++11,C++,Multithreading,C++11,我有一个服务器类型的应用程序,我有一个问题,确保线程在完成之前没有被删除。下面的代码几乎代表了我的服务器;需要进行清理以防止列表中死线的累积 using namespace std; class A { public: void doSomethingThreaded(function<void()> cleanupFunction, function<bool()> getStopFlag) { somethingThread = thread(

我有一个服务器类型的应用程序,我有一个问题,确保线程在完成之前没有被删除。下面的代码几乎代表了我的服务器;需要进行清理以防止列表中死线的累积

using namespace std;

class A {
public:
    void doSomethingThreaded(function<void()> cleanupFunction, function<bool()> getStopFlag) {
       somethingThread = thread([cleanupFunction, getStopFlag, this]() {
          doSomething(getStopFlag);
          cleanupFunction();
       });

    }
private:
    void doSomething(function<bool()> getStopFlag);
    thread somethingThread;
    ...
}

class B {
public:
    void runServer();

    void stop() {
        stopFlag = true;
        waitForListToBeEmpty();
    }
private:
    void waitForListToBeEmpty() { ... };
    void handleAccept(...) {
        shared_ptr<A> newClient(new A());
        { 
            unique_lock<mutex> lock(listMutex);
            clientData.push_back(newClient);
        }
        newClient.doSomethingThreaded(bind(&B::cleanup, this, newClient), [this]() {
            return stopFlag;
        });
    }

    void cleanup(shared_ptr<A> data) {
        unique_lock<mutex> lock(listMutex);
        clientData.remove(data);
    }

    list<shared_ptr<A>> clientData;
    mutex listMutex;
    atomc<bool> stopFlag;
}
使用名称空间std;
甲级{
公众:
void dosomethingthread(函数cleanupFunction,函数getStopFlag){
somethingThread=线程([cleanupFunction,getStopFlag,this](){
剂量测定(getStopFlag);
cleanupFunction();
});
}
私人:
无效剂量测定(函数getStopFlag);
穿一些东西阅读;
...
}
B类{
公众:
void runServer();
无效停止(){
stopFlag=true;
waitForListToBeEmpty();
}
私人:
void waitForListToBeEmpty(){…};
无效手浸接受(…){
共享_ptr newClient(newa());
{ 
唯一锁(listMutex);
clientData.push_back(newClient);
}
doSomethingthread(绑定(&B::cleanup,this,newClient),[this](){
返回停止标志;
});
}
空洞清理(共享的ptr数据){
唯一锁(listMutex);
clientData.remove(数据);
}
列出客户数据;
互斥列表互斥;
atomc停止标志;
}
问题似乎是析构函数以错误的顺序运行-即共享的_ptr在线程的函数完成时被析构函数,这意味着“A”对象在线程完成之前被删除,在调用线程的析构函数时导致havok

i、 e。 调用清除函数 所有对此(即一个对象)的引用都已删除,因此调用析构函数(包括该线程的析构函数) 再次调用此线程的析构函数--哦,不

我已经研究过一些替代方法,比如维护一个“待删除”列表,该列表定期被另一个线程用来清理主列表,或者对共享指针使用一个延时的deletor函数,但这两种方法看起来都有点笨重,可能会有争用条件


有人知道这样做的好方法吗?我找不到一种简单的方法来重构它,使其正常工作。

线程是可连接的还是可分离的?我没有看到任何
分离
,
这意味着在没有
这是一个致命的错误。你可以试着把它拆开,
尽管这会使干净的关机变得有些复杂。(关于
当然,对于很多服务器来说,永远不应该关闭
无论如何。)否则:我过去所做的就是创造
收割者线;一种只连接任何一条线的线
杰出的线程,清理后,他们

我可以补充一点,这是一个很好的例子 共享ptr不合适。你想完全控制一切 当删除发生时;如果分离,则可以在 清理功能(但坦率地说,只需使用
删除此项;
A::doSomethingthread
中lambda的末尾,似乎更 可读);否则,您在加入后,在 收割者线

编辑:

对于“收割者”线程,类似于以下内容的操作应该有效:

class ReaperQueue
{
    std::deque<A*> myQueue;
    std::mutex myMutex;
    std::conditional_variable myCond;
    A* getOne()
    {
        std::lock<std::mutex> lock( myMutex );
        myCond.wait( lock, [&]( !myQueue.empty() ) );
        A* results = myQueue.front();
        myQueue.pop_front();
        return results;
    }
public:
    void readyToReap( A* finished_thread )
    {
        std::unique_lock<std::mutex> lock( myMutex );
        myQueue.push_back( finished_thread );
        myCond.notify_all();
    }

    void reaperThread()
    {
        for ( ; ; )
        {
            A* mine = getOne();
            mine->somethingThread.join();
            delete mine;
        }
    }
};
类重新排队
{
std::deque myQueue;
std::mutex myMutex;
std::条件_变量myCond;
A*getOne()
{
std::锁(myMutex);
myCond.wait(锁,[&](!myQueue.empty());
A*results=myQueue.front();
myQueue.pop_front();
返回结果;
}
公众:
void readyteau(A*成品螺纹)
{
std::唯一锁(myMutex);
myQueue.push_back(完成的_线程);
myCond.notify_all();
}
void reaperThread()
{
对于(;;)
{
A*mine=getOne();
mine->somethingThread.join();
删除地雷;
}
}
};
(警告:我还没有测试过这个,我尝试过使用C++11 功能性。我只是在过去实际实现了它, 使用pthreads,因此可能会出现一些错误 不过,原则应该成立。)

要使用,请创建一个实例,然后启动线程调用
reaperThread
。在清理每个线程时,调用
readyteau

要支持完全关闭,您可能需要使用两个队列:您 在创建第一个线程时将其插入第一个线程,然后 将其从第一个移动到第二个(对应于
readyteau
中的
myQueue
,如上)。要关机,请等待 直到两个队列都为空(不在中启动任何新线程)
当然是这个时间间隔。

问题在于,由于您通过共享指针管理
A
,因此线程lambda捕获的
this
指针实际上需要是一个共享指针,而不是原始指针,以防止其悬空。问题是,当您没有实际的共享ptr时,没有简单的方法从原始指针创建共享ptr

解决这个问题的一种方法是使用this中的共享:

class A : public enable_shared_from_this<A> {
public:
    void doSomethingThreaded(function<void()> cleanupFunction, function<bool()> getStopFlag) {
       somethingThread = thread([cleanupFunction, getStopFlag, this]() {
          shared_ptr<A> temp = shared_from_this();
          doSomething(getStopFlag);
          cleanupFunction();
       });
A类:公共启用\u共享\u{
公众:
void dosomethingthread(函数cleanupFunction,函数getStopFlag){
somethingThread=线程([cleanupFunction,getStopFlag,this](){
shared_ptr temp=来自_this()的共享_;
剂量测定(getStopFlag);
cleanupFunction();
});
这将为
A
对象创建一个额外的共享ptr,使其在线程结束之前保持活动状态

请注意,James Kanze指出的
join
/
detach
仍然存在问题——每个线程在销毁前必须对其调用一次
join
detach
。如果不关心t线程退出值

如果在单个
a
上多次调用
doSomethingThreaded
,也可能出现问题
class A {
public:
    void doSomething(function<bool()> getStopFlag) {
        ...
    }
private:
    ...
}

class B {
public:
    void runServer();

    void stop() {
        stopFlag = true;
        waitForListToBeEmpty();
    }
private:
    void waitForListToBeEmpty() { ... };
    void handleAccept(...) {
        shared_ptr<A> newClient(new A());
        { 
            unique_lock<mutex> lock(listMutex);
            clientData.push_back(newClient);
        }
        thread clientThread([this, newClient]() { 
            // Capture the shared_ptr until thread over and done with.

            newClient->doSomething([this]() {
                return stopFlag;
            });
            cleanup(newClient);
        });
        // Detach to remove the need to store these threads until their completion.
        clientThread.detach();
    }

    void cleanup(shared_ptr<A> data) {
        unique_lock<mutex> lock(listMutex);
        clientData.remove(data);
    }

    list<shared_ptr<A>> clientData; // Can remove this if you don't 
                                    // need to connect with your clients.
                                    // However, you'd need to make sure this 
                                    // didn't get deallocated before all clients 
                                    // finished as they reference the boolean stopFlag
                                    // OR make it a shared_ptr to an atomic boolean
    mutex listMutex;
    atomc<bool> stopFlag;
}