C++并发编程(CH02)启动thread-01]

Launching a thread

所有callable对象都可以作为thread的参数

void do_some_work();
std::thread my_thread(do_some_work);

class background_task
{
public:

  void operator()() const
  {

    do_something();
    do_something_else();
  }
};
background_task f;
std::thread my_thread(f);

下面的声明有问题

std::thread my_thread(background_task());

它是一个函数名字为 my_thread 返回值h死 std::thread
,函数的参数,是一个无返回无参数的函数指针.所以最好使用下面的声明形式.

std::thread my_thread((background_task()));
std::thread my_thread{background_task()}; 

如何声明一个线程变量,而不运行它。也可以使用lambda表达式

std::thread my_thread([]{
                          do_something();
                          do_something_else();
                      });
  1. 需要注意的,如果你不detach和join线程.那么线程在主线程退出之后,会被terminate掉.

  2. 如果你detach一个线程,那么即便线程对象销毁后,此线程也可能会跑很长一段时间.thread对象只是C++用来管理计算机线程的对象.如果你detach它了,这个对象自然就可以释放和销毁了.但是计算机的线程却仍然在计算机上运行.

把局部变量带入thread里面了,会发生未定义行为.不要犯错

struct func
{
    int& i;
    func(int& i_):i(i_){}
    void operator()()
    {
        for(unsigned j=0;j<1000000;++j)
        {
            do_something(i);                // 1. Potential access to dangling
        }
    }
};
void oops()
{
    int some_local_state=0;
    func my_func(some_local_state);
    std::thread my_thread(my_func);
    my_thread.detach();                    // 2. Don’t wait for thread to finish
}                                          // 3. New thread might still be running

如果线程参数是一个callable对象,那么它的变量是被拷贝了的。但是如果里面有指针和引用也不能避免,访问被释放资源的区域。所以也应当小心,不要让这样的情况发生.

等待线程结束

你只能调用一次join.无论你是调用thread的join还是detach.在这这时候线程的joinable()都会返回false.你只能操作一次join
or detach.

面对异常:调用join的时机应该斟酌好,因为主线程可能发生异常.你就没有机会去join一个线程或者detach一个线程.

struct func;    // <-- See definition in listing 2.1
void f()
{
  int some_local_state=0;
  func my_func(some_local_state);
  std::thread t(my_func);
  try
    {
      do_something_in_current_thread();
    }
  catch(...)
    {
      t.join(); // <-- 1

      throw;
    }
  t.join();     // <-- 2
}

这种处理方式不好,用try and
catch的话.很难保证所有的异常都被考虑进去了.所以应该使用RAII方法(Resource
Acquisition Is Initialization)

class thread_guard
{
  std::thread& t;
public:
  explicit thread_guard(std::thread& t_):
    t(t_)
  {}
  ~thread_guard()
  {
    if(t.joinable())                        // <-- 1
      {
        t.join();                           // <-- 2
      }
  }
  thread_guard(thread_guard const&)=delete; // <-- 3
  thread_guard& operator=(thread_guard const&)=delete;
};
struct func;                                // <-- See definition in listing 2.1
void f()
{
  int some_local_state=0;
  func my_func(some_local_state);
  std::thread t(my_func);
  thread_guard g(t);
  do_something_in_current_thread();
}                                           // <-- 4

= d e l e t e =delete =delete
禁止编译器提供默认函数,比如默认复制构造函数和拷贝构造函数。那么对这些对象的复制拷贝会造成编译器错误.

让thread在后台运行

  1. 线程一旦detach就会被C++ Runtime Library接管,用户不能在通过thread
    对象join和控制
std::thread t(do_background_work);
t.detach();
assert(!t.joinable());

如果t.joinable()返回false是不能detach的.

void edit_document(std::string const& filename)
{
  open_document_and_display_gui(filename);
  while(!done_editing())
    {
      user_command cmd=get_user_input();
      if(cmd.type==open_new_document)
        {
          std::string const new_name=get_filename_from_user();
          std::thread t(edit_document,new_name); //<--1
          //(sai:传递参数的一种形式,也可以是使用callable object with member data in it)
          t.detach();                            //<--2
        }
      else
        {
          process_user_input(cmd);
        }
    }
}

注意
:虽然你detach但是主线程退出了.你的所有线程也会被terminate掉.所以detach的有效性需要得到主线程支持.所谓主线程,就是你run
main函数的那个线程.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值