[多线程并发并行]_[C/C++11]_[如何取消线程-停止线程]

场景

  1. 在开发多线程程序时,经常由于需要重新执行任务从而取消(停止)工作线程。C++11目前并没有很好的取消线程执行的机制。那么我们应该如何实现取消线程呢?

说明

  1. C++11使用库进行线程间数据通讯,也可以利用它来进行控制线程停止。但是没有pthread那么强大,pthread有取消点函数,线程执行到取消点函数就会判断如何线程状态设置为取消,那么就会调用预先设定的线程清理函数清理资源,而取消点之后的代码块不会执行,最后再中止线程。而C++11并没有取消点的设计。只有在工作线程里判断某个值如果是取消设置的值,那么就会根据代码里的行为继续执行非业务代码,比如跳出循环。

  2. C++11有了promise,我们可以通过它来调用set_value来把future设置为ready状态,之后工作线程里的future通过wait_for方法来判断线程状态是否改变。之后跳出工作循环。

  3. 除了使用promise对象,我们还可以使用一个变量判断是否已经停止,这个变量可以是atomic_int也可以是volatie类型的变量,其实和promise修改状态值是一样的,性能更高。

例子

  1. 以下例子实现了运行时中止两个工作线程。

test-thread-stop.cpp


#include 
#include "utils.h"
#include 
#include 
#include 
#include 
#include 
using namespace std;

void ThreadWork(shared_future<void> ft){

    // 注意,线程只有执行到循环判断条件里才会中止,如果正在执行耗时任务,是不会停止的.
    //     所以这种通用的停止线程的模式也有弊端.
    while(ft.wait_for(chrono::milliseconds(1)) == future_status::timeout){
        
        log("In ThreadWork thread id",this_thread::get_id());
        // 模拟执行耗时任务.  
        this_thread::sleep_for(chrono::milliseconds(500));
    }
    log("ThreadWork END thread id",this_thread::get_id());
}

// 方式1:使用promise安全停止线程工作.
void TestThreadStop_1(){

    print("=========================== TestThreadStop_1 BEGIN ==============================");
    promise<void> p;
    shared_future<void> sp(p.get_future());
     
    auto result1 = std::async(std::launch::async, bind(ThreadWork,sp));
    auto result2 = std::async(std::launch::async, bind(ThreadWork,sp));

    // 让工作线程执行5秒钟
    this_thread::sleep_for(chrono::seconds(5));

    // 设置future状态为 future_status::ready,线程里的wait_for会返回值future_status::ready导致循环退出
    p.set_value();

    // 等待工作线程执行结束. 如果是线程调用,还需要优化停止方式.比如显示动画已表示正在停止中...
    result1.get();
    result2.get();
    print("TestThreadStop_1 END");
}


// 方式2:使用原子变量安全停止线程工作.
void TestThreadStop_2(){

    print("=========================== TestThreadStop_2 BEGIN ==============================");
    atomic_bool stopped(false);

    auto func = [](atomic_bool* ab) {
        while(!(*ab)){

            log("In lambda func thread id", this_thread::get_id());
            // 模拟执行耗时任务.
            this_thread::sleep_for(chrono::milliseconds(500));
        }
        log("lambda func END thread id", this_thread::get_id());
    };

    auto result1 = std::async(std::launch::async,func,&stopped);
    auto result2 = std::async(std::launch::async,func,&stopped);

    // 让工作线程执行5秒钟
    this_thread::sleep_for(chrono::seconds(5));

    // 设置停止标记为true.
    stopped = true;

    // 等待工作线程执行结束. 
    result1.get();
    result2.get();
    print("TestThreadStop_2 END");
}

// https://thispointer.com/c11-how-to-stop-or-terminate-a-thread/
int main(int argc, char const *argv[])
{
    TestThreadStop_1();
    TestThreadStop_2();
    getchar();
    return 0;
}

部分输出

=========================== TestThreadStop_1 BEGIN ====
=
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
In ThreadWork thread id=0x60006cd20
In ThreadWork thread id=0x60006d280
ThreadWork END thread id=0x60006cd20
ThreadWork END thread id=0x60006d280

参考

Pthread的线程取消特性

对工作线程进行简单控制-暂停-继续-停止

pthread_cancel

c11-how-to-stop-or-terminate-a-thread

你可能感兴趣的:(C/C++多线程并发并行,C++11,thread,停止,取消,线程)