C++多线程

{ 1 }CPP_线程管理的基础

2018-11-23  本文已影响116人  庄阿莫

一,启动线程

1. 使用C++线程库启动线程,即为构造std::thread对象:

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

std::thread构造方法

class A
{
public:
  void operator()() const
  {
     std::cout << "hello" << std::endl;
  }
};

A a;
std::thread my_thread(a);

std::thread my_thread(a);调用函数对象a() 传入thread中 ,并把函数对象a 复制到新线程的存储空间中,函数对象的执行和调用都在线程的内存空间中进行。

注意:

std::thread my_thread( A() );//A()是一个临时的函数对象

这段代码被解析为:
这是一个函数声明,函数名为my_thread。它可以接收一个没有参数的,并且会返回对象A的函数指针。my_thread函数的返回值是std::thread类型。

怎么解决?
使用多组括号,初始化语法 或者 前面代码 都可以避免这个问题:
std::thread my_thread( (A()) );
std::thread my_thread{ A() };

struct F
{
  int &i;
  func(int &i_) : i( i _ )  { }

  void operator() ()
  {
    for(unsigned j = 0; j < 100000; ++j)
    {
        std::cout << i << std::endl;
     }
  }
}

void oop()
{
   int number = 0;
   F my_f(unmber);
   std::thread my_f(my_f);
   my_f.detach();
}

由于不等待线程结束, 当oop()执行完成时, 新线程中的函数可能还在运行。 如果线程还在运行, 它就会去调用do_something(i)函数,这时,引用对象 i 已经被销毁了。

二,等待线程完成

如果需要等待线程, std::thread 实例可以使用join()。

class func1{//仿函数对于多线程的运用
public:
    int &a;
    explicit func1(int &a_) : a(a_) {}

    int operator()(int c)
    {
        for(;a < c; ++a)
        {
            cout << a << endl;
        }
        cout << a << endl;
        return a;
    }
};

int main()
{
    int st = 6;
    func1 f(st);

    int c = 10;
    std::thread my_thread (f, c);
    my_thread.join();

    return 0;
}

三,特殊情况下的等待

当倾向在无异常的情况下使用join()时, 需要在异常处理过程中调用join(), 从而避免生命周期的问题。

struct F
{
  int &i;
  func(int &i_) : i( i _ )  { }

  void operator() ()
  {
    for(unsigned j = 0; j < 100000; ++j)
    {
        std::cout << i << std::endl;
     }
  }
}

class G
{
  std::thread& t;

public:
  explicit G(std::thread& t_) : t(t_) {}
  ~G()
  {
    if(t.joinable()) 
    {
      t.join(); 
    }
  } 

  G( G const& )=delete;//不让编译器自动生成,因为这可能会弄丢已经加入的线程。
  G& operator= ( G const& )=delete;
};

struct F;

void oop()
{
  int data = 0;
  F struct_my_f(data);
  std::thread my_t(struct_my_f);
  G my_g(t);
  do_something_in_current_thread();
} 

函数oop() 执行完,对象my_g 也会被销毁, 即使do_something_in_current_thread() 抛出一个异常, 这个销毁依旧会发生。

四,后台运行线程

如果不想等待线程结束, 可以分离(detaching)线程, 从而避免异常安全(exception-safety)问题。 由于使用detach()会让线程在后台运行,如果线程分离, 那么就不可能有 std::thread 对象能引用它, 分离线程的确在后台运行, 所以分离线程不能被加入。

一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。

注意:

当在 std::thread 对象中分离线程时,不能对没有执行线程的 std::thread 对象使用detach()。因为和 join()的使用条件相同, 所以可以用同样的方式进行检查,当 std::thread 对象使用 t.detach() 之前,先使用t.joinable()检测该线程是否为可执行线程,如果返回的是true,就可以使用了。

上一篇下一篇

猜你喜欢

热点阅读