C++ 线程结束

问题描述 投票:0回答:1

我正在尝试学习一些正确的线程管理,但我对这个人为的示例遇到了一些问题。这个想法是“Holder”类可以启动一个作业,它是“Wait”类的一个实例,它触发一个线程做一些事情(等待一段时间),然后调用“Holder”中的回调来做一些事情一些清理或其他什么。 我将“等待”实例放入 std::vector 中,当回调告诉我它已完成时。我将其从列表中删除。

更新:更正注释掉的行

//waitlist.erase(it); // 转储等待对象

如果我调用上面的行来指示作业已完成并将其从“列表”中删除,则会导致主线程过早退出,为什么?正确的去除方法是什么?

#include <chrono>
#include <ctime>
#include <functional>
#include <iostream>
#include <thread>
#include <vector>

using Time = std::chrono::system_clock;
using Seconds = std::chrono::seconds;
using Timepoint = Time::time_point;

class Wait {
private:
    Timepoint target;
    std::thread thread;

public:
    Wait(unsigned int waitFor, unsigned short id, std::function<void(unsigned int)> callback_)
    {
        std::cout << "new Wait objet needs to wait for: " << waitFor << " seconds" << std::endl;
        target = Time::now() + Seconds(waitFor);

        // Create a thread to notify us when complete

        thread = std::thread([callback_, waitFor, id]() {
            std::this_thread::sleep_for(Seconds(waitFor));
            std::cout << "from thread: " << std::this_thread::get_id() << std::endl;
            callback_(id);
        });
        
    }

    bool isDone() 
    {
        Timepoint now = Time::now();
        std::chrono::duration<float> difference = now - target;
        return (difference.count() > 0); // Thanks @Jesper
    }
};

class Holder {
private:
    std::vector<Wait> waitlist;

public:
    unsigned short addTask(unsigned int waitFor)
    {
        unsigned int sz = waitlist.size();
        waitlist.push_back(Wait(waitFor, sz, std::bind(&Holder::callback, this, std::placeholders::_1)));

        return waitlist.size() - 1;
    }

    bool isDone(unsigned int n) 
    {
        if (waitlist.size() >= n) {
            return waitlist.at(n).isDone();
        } 
        else return false; // failed
    }

    void callback(unsigned int id)
    {
        std::cout << "All done with Wait object" << std::endl;
        
        auto it = waitlist.begin() + id;
        /* comment/uncomment next line*/
        //waitlist.erase(it); // dump the wait object
    }
};

int main() 
{
    Holder h;
    // Create a task which spawns a thread, which notifies us when complete
    unsigned int id1 = h.addTask(3);
    
    // Just to show that while main thread is running, the completion status
    // of thread changes
    for (auto c = 0; c < 5; c++)
    {
        std::this_thread::sleep_for(Seconds(1));
        std::cout << "from main: " << std::this_thread::get_id() << " - " << h.isDone(id1) << std::endl;
    }

    // Just to show the main thread continues on. It doesn't when line mentioned 
    // earlier is uncommented
    while(1) {
        std::this_thread::sleep_for(Seconds(1));
        std::cout << "Doing other stuff.." << std::endl;
    }

    return 0;
}

预期输出:

new Wait objet needs to wait for: 3 seconds
from main: 140234566031168 - 0
from main: 140234566031168 - 0
from thread: 140234566026816
All done with Wait object
from main: 140234566031168 - 1
from main: 140234566031168 - 1
from main: 140234566031168 - 1
Doing other stuff..
Doing other stuff..
Doing other stuff..
Doing other stuff..
Doing other stuff..

任何关于我忽略的(我确定基本)前提的见解/指导将不胜感激。

保罗

c++ multithreading callback
1个回答
0
投票

好的, 我明白我做错了什么。回调(从 Wait 对象中实例化的线程执行)试图删除容纳该线程的 Wait 对象,该对象调用线程的析构函数并导致主线程存在。

使用 std::async 可以解决连接/分离问题(我猜类似于上面提到的 C++20 的 std::jthread 选项),但您可以简单地检查它是否已完成,例如;

if (async_task.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // async done

一旦我有办法检查它是否完成,我可以简单地检查是否完成,然后从“Holder”类中的向量中删除该任务。

我不能对线程做同样的事情,因为如果我使用 join(),我必须等待它,并且我不想要阻塞调用,如果我使用 detach(),它将把它与main 实例,我不知道它何时/是否完成。如果实例化的线程在没有看到其中任何一个的情况下终止,它会导致主线程终止,这就是为什么我在线程终止后没有进入“做其他事情...”部分。

© www.soinside.com 2019 - 2024. All rights reserved.