C++ std::线程在连接之前终止

EYa*_*umi 1 c++ multithreading

我正在编写 C++ 代码来在不同线程上执行任务并等待结果返回主函数。

每个线程可以采取不同的计时,并可能导致正确或不正确的结果。

我按如下方式启动线程:

std::thread p1(&process1, (void*)&p1Data);
std::thread p2(&process2, (void*)&p2Data);
std::thread p3(&process3, (void*)&p3Data);
.
.
.
Run Code Online (Sandbox Code Playgroud)

(多个线程就是这样创建的)。

流程功能可以总结如下:

\\ThreadData is a structure that contains all the data for the thread
void process1(void *data)
{
    ThreadData * tData = (ThreadData*) data;
    ResultObject * result = data->result;
    .
    .
    .
    \\Process to calculate Result using data
}
Run Code Online (Sandbox Code Playgroud)

在启动这些线程后,我将在 main 中加入它们以等待最终结果,然后检查正确的结果。

p1.join();
p2.join();
.
.
.

p1result = p1Data.result;
p2result = p2Data.result;
.
.
.
.
.
.

if (p1result)
{
    return p1Data;
}

if (p2result)
{
    return p2Data;
}


Run Code Online (Sandbox Code Playgroud)

但问题是(为了简单起见,我将认为 p1 是最快的线程)如果 p1 完成并获得正确的结果,我仍然被迫等待所有其他线程的连接以获得最终结果,而 p1 已完成第一个可以包含正确的,我可以终止它。

我如何在每个线程完成时检查结果是否正常,以便我可以终止剩余的线程,而无需等待它们完成(即,如果 p2 在 p1 之前完成并且 p2 的结果是可以接受的,我可以返回 p2Data 并终止所有剩余线程而不需要)

Qui*_*mby 5

不幸的是,没有std::shared_promise原子set_if_still_empty()is_empty()方法。此外,线程不能从外部终止(这是一件好事),C++20 使用std::jthread它的停止标记解决了这个问题,请随意使用它。我将只使用std::atomic_bool标志。在这两种情况下,线程本身必须监视令牌并根据请求自行终止。

我的解决方案用于std::promise存储结果,如果结果已设置且其设置器是原子的,则会抛出异常,因此不需要额外的锁。

#include <future>
#include <thread>
#include <atomic>

using result_t=int;

void worker(std::promise<result_t>& promise,std::atomic_bool& stop_requested){
    //periodically check flag
    while(!stop_requested){
        // do work
        
        // if result
        result_t result=1;
        try{
            promise.set_value(result);
            // Terminate other threads soon, including us.
            stop_requested=true;
            return; // Not need if there is no work after `try` statement.
        }
        catch(const std::future_error&)//Already set
        {
            return;

        }     
    }
}

int main() {

    std::promise<result_t> promise;
    std::atomic_bool stop_token= false;

    std::thread w1(worker,std::ref(promise),std::ref(stop_token));

    auto future = promise.get_future();
   
    result_t result = future.get();
    // All threads should terminated soon after they check the token.
    //stop_token=true;// Is not necessary because it is set by the winning thread.

    w1.join();
    
}
Run Code Online (Sandbox Code Playgroud)

或者,std::optional<result_t>也可以使用+lock。但是您必须定期锁定以检查结果是否存在以及线程是否应该退出。