线程管理

2018-04-23  本文已影响15人  wenmingxing

本文主要内容包括:启动新线程;等待线程与分离线程;线程唯一标识符。

I、线程管理的基础

每个线程都有各自的入口函数。最简单情况下,任务通常是无参数无返回值的函数。这个函数在其所属的线程上运行,直到函数执行完毕,线程也就结束了。

1.1 启动线程

使用C++线程库启动线程,可以归结为构造std::thread对象,std::thread可以用可调用类型构造,将带有函数调用符类型的实例传入thread类中,替换默认的构造函数,下面的代码使用函数对象来完成对thread的构造:

class background_task {
public:
    void operator()() const {
        do_something();
        do_something_else();
    }
};

background_task f;    //必须使用一个命名的变量
std:::thread my_thread(f);

这里需要注意一个问题,当把函数对象传入到线程的构造函数中时,需要避免一些语法解析问题:如果传递了一个临时变量,而不是一个命名的变量,C++编译器会将其解析为函数声明,而不是类型对象的定义:

std::thread my_thread(background_task());
这里相当于声明了一个名为my_thread的函数,返回一个thread对象,而非启动了一个线程。

可以通过以下两种方式解决这个问题:

std::thread my_thread((background_task()));
std::thread my_thread{background_task()};  //新统一的初始化语法

或者使用lambda表达式

std::thread my_thread([] {
    do_something();
});
1.2 join 与 detach

1、join函数为等待线程完成,确保线程在函数完成前结束,并且只能对一个线程使用一次join

2、detach会让线程在后台运行,这就意味着主线程不能与之产生直接交互。不会等待这个线程结束。

3、joindetach的区别可以理解为:在调用方法之后,主线程是否还有对线程的控制权

II、向线程函数传递参数

#include<thread>
#include<iostream>
#include<string>

using namespace std;

void print(string& str) {
    cout << str << endl;
}

int main() {
    string str = "hello";
    thread th1(print, ref(str));     //需要确保传入print的参数与其定义的引用一致

    th1.join();

    return 0;
}

III、转移线程所有权

执行线程的所有权可以在std::thread实例中移动,下面是一个例子:

void some_function();
void some_other_function();
std::thread t1(some_function);
std::thread t2 = std::move(t1);
t1 = std::thread(some_other_function);
std::thread t3;
t3 = std::move(t2);
t1 = std::move(t3);

IV、识别线程

调用get_id()方法可以直接获取线程id:

#include<thread>
#include<iostream>
#include<string>

using namespace std;

void print(string str) {
    cout << str << endl;
}

int main() {
    cout << this_thread::get_id() << endl;  //通过this_thread获得当前线程标识

    thread th1(print, "id");

    cout << th1.get_id() << endl;   //通过get_id识别线程
    th1.join();

    return 0;
}

【参考】
[1] 《C++ Concurrency In Action》

上一篇 下一篇

猜你喜欢

热点阅读