跳转至

jthread

title: jthread 和 thread不同?
1. jthread 可以控制线程的取消/停止。(需要通过线程函数含std::stop_token参数,内部调用stop_token::stop_requested()判断)
2. jthread 析构时会自动join,执行线程。(析构先调用request_stop() 再调用 join())
  • 功能:jthread 和 thread 功能一样,启动一个线程。jthread 逻辑上保有一个内部的 std::stop_source 类型私有成员,它维持共享停止状态。 jthread 的构造函数接受一个 std::stop_token 作为其首参数, jthread 将从其内部的 stop_source 传递它。这允许函数在其执行中检查是否已请求停止,而若已请求则返回

1 停止信号函数

  • get_stop_source :返回与线程的停止状态关联的 stop_source 对象
  • get_stop_token :返回与线程的共享停止状态关联的 stop_token 对象
  • request_stop :请求执行经由线程的共享停止状态停止(发出停止信号,实际等价于 get_stop_source().request_stop ()

3 stop_source

stop_source 类提供发出停止请求的方式。stop_source 包含 stop_token 对象。

4 stop_token

stop_token 内部有一个停止状态变量,可以检测这个状态,以便决定是否中止线程。类提供是否已经或能对其所关联的 std:: stop_source 对象作出停止请求的方法。 - 示例

int test_jthread()
{
    auto worker1=[] (std::stop_token token,int i) {
        std::cout<<"worker1 thread " << i<<"\n";
    };
    auto worker2=[] (int i) {
        std::cout<<"worker2 thread "<< i<<"\n";
    };  
    std::stop_token token;
    std::jthread  th1(worker1,1);   // th1.get_stop_token() as the first argrment
    std::jthread  th2(worker2,2);   //same as thread
    std::jthread  th3(worker1, token, 2);   //same as thread
}

5 stop_callback

stop_callback 类模板提供对关联的 std:: stop_token 对象注册回调函数的 RAII 对象类型,使得将在 std:: stop_token 的关联 std:: stop_source 被请求停止时调用回调函数。 - 示例

//serializing the output with thread id
void sout(const char * s)
{
    static std::mutex mtx;
    const std::lock_guard<std::mutex> lock(mtx);
    std::cout<<"["<<std::this_thread::get_id() <<"]"<<s<<'\n';
}
Void test_stopcallback()
{
    sout("main thread");    
    auto worker=[] (std::stop_token token) {
        sout("worker thread");
        std::mutex mutex;
        std::unique_lock lock(mutex);
        std::condition_variable_any().wait(lock, token,
            [&token] { return token.stop_requested(); });
        sout("worker thread end");          
    };
    std::stop_source  source;
    auto token=source.get_token();
    std::stop_callback callback_stop(token, [] {
        sout( "Stop callback executed");
    });

    std::jthread th(worker, token);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    if(source.request_stop())  sout("stop OK");// 调用request_stop(),触发stop_callback的回调函数
}
  • 可能输出
[139788821808960]main thread
[139788803913472]worker thread
[139788821808960]Stop callback executed
[139788821808960]stop OK
[139788803913472]worker thread end

2 示例

#include <chrono>
#include <iostream>
#include <thread>

using namespace ::std::literals;

int main() {

  std::cout << std::endl;

  std::jthread nonInterruptable([] { // (1)
    int counter{0};
    std::cout << "thread id: " << std::this_thread::get_id() << std::endl;
    while (counter < 10) {
      std::this_thread::sleep_for(0.2s);
      std::cerr << "nonInterruptable: " << counter << std::endl;
      ++counter;
    }
  });

  std::jthread interruptable([](std::stop_token itoken) { // (2)
    int counter{0};
    std::cout << "thread id: " << std::this_thread::get_id() << std::endl;
    while (counter < 10) {
      std::this_thread::sleep_for(0.2s);
      if (itoken.stop_requested())// (3)处理线程停止信号
        return; 
      std::cerr << "interruptable: " << counter << std::endl;
      ++counter;
    }
  });

  std::this_thread::sleep_for(1s);

  std::cerr << std::endl;
  std::cerr << "Main thread interrupts both jthreads" << std::endl;
  nonInterruptable.request_stop();//请求停止,但线程函数没有处理此信号
  //interruptable.get_stop_source().request_stop();
  interruptable.request_stop(); // (4)请求停止

  std::cout << std::endl;
}
  • 可能输出
[shw@rocky jthread]$ ./a.out 

thread id: 140513660630592
thread id: 140513669023296
interruptable: 0
nonInterruptable: 0
nonInterruptable: 1
interruptable: 1
nonInterruptable: 2
interruptable: 2
nonInterruptable: 3
interruptable: 3

Main thread interrupts both jthreads

nonInterruptable: 4
nonInterruptable: 5
nonInterruptable: 6
nonInterruptable: 7
nonInterruptable: 8
nonInterruptable: 9