C++11新特性--线程库相关

线程的创建

std::thread t() 提供线程函数或者函数对象
t.join() 阻塞线程直到线程函数执行完毕
t.detach() 如果不希望线程被阻塞执行就调用detach(),但是这会导致线程和线程对象分离。

std::thread创建的线程在出了作用域之后会被析构,如果这时候线程函数还没有执行完的话就会发生错误。

线程不能复制,但是可以移动

std::thread t(func);
std::thread t2(std::move(t));

当move之后,线程对象t就不再代表任何线程了。
线程还可以使用std::bind或者lambda表达式创建线程

std::thread t(std::bind(func, 1, 2));
std::thread t1([](int a, double b){}, 1, 2);

必须注意必须要保证线程函数的生命周期要在线程对象std::thread的生命周期内

获取当前线程id

std::thread t(func);
t.get_id();

线程休眠

std::this_thread::sleep_for(std::chrono::seconds(3));

std::this_thread类保存了当前线程的一些信息参数和方法

互斥量

std::mutex
std::timed_mutex
std::recursive_mutex
std::recursive_timed_mutex

使用mutex的时候必须lock和unlock成对出现,为了防止有遗忘,这里采用了类似RAII的机制,即在类的构造函数中lock,而在析构函数中去unlock。使用的是lock_guard。

std::mutex g_lock;
std::lock_guard::mutex> locker(g_lock);

那通过以上的代码就不需要担心会忘记unlock这个步骤了,当locker在出作用域的时候会被析构,会自动调用unlock进行解锁的。

递归锁比起非递归锁,效率会低一些。

条件变量

条件变量需要和互斥量配合起来使用

condition_variable:配合std::unique_lock进行wait操作
condition_variable_any: 和任意带有lock、unlock的mutex都可以搭配使用,比较灵活但是效率比condition_variable差。

std::unique_lock和std::lock_guard的差别在于前者可以自由地释放mutex,而后者必须是在出作用域的时候才能释放。

调用条件变量的wait()方法的时候,会先释放掉互斥量,然后等到被其他线程notify的时候然后再去尝试重新获得mutex。

原子变量

std::atomic

call_once/once_flag

在多线程环境中,有时候为了保证某个函数只是执行一次的话,可以使用std::call_once()。

std::once_flag flag;

void do_once()
{
    std::call_once(flag, [](){/*do something*/});
}

int main()
{
    std::thread t(do_once);
    std::thread t1(do_once);

    t.join();
    t1.join();
}

上面的lambda表达式的行为只会执行一次。

异步操作类

主要有std:future, std::promise, std::package_task

std::future作为异步结果的传输通道,可以获取线程函数的返回值

std::future_status status;
do {
    status = future.wait_for(std::chrono::seconds(3));
    if(status == std::future_status::deferred)
        std::cout << "deferred\n";
    else if(status == std::future_status::timeout)
        /*TODO*/
    else if(status == std::future_status::ready)
        /*TODO*/
} while(status != std::future_status::ready)

std::promise用来包装一个值,将数据和future绑定起来

std::promise ptr;
std::thread t([](std::promise &p){p.set_value_at_thread_exit(9);}, std::ref(ptr));
std::future f = ptr.get_future();
auto r = f.get();

std::package_task用来包装一个可调用对象,将函数和future绑定起来,以便异步调用。

int func(int x) {return x+2;}

int main()
{
    std::package_task<int(int)> tsk(func);
    std::future<int> fut = tsk.get_future();
    std::thread(std::move(tsk), 2).detach();
    int value = fut.get(); //4

    vector<std::shared_future<int>> v;
    auto f = std::async(std::launch::async, [](int a, int b){return a+b;}, 2, 3);
    v.push_back(f);
}

future是不能复制的,不能放到容器里,需要用到shared_future。

线程异步操作函数async

async可以用来直接创建异步的task
async(std::launch::async|std::launch::deferred, f, args…)
第一个参数是线程创建的策略,有两种策略:async表示在调用函数的时候立即创建线程,而deferred是延迟加载创建线程,要到调用future.get()或者wait的时候才创建线程。
第二个参数是线程函数
第三个参数是线程函数的参数

std::future<int> f1 = std::async(std::launch::async, [](){return 8;});
cout << f1.get() << endl;

std::future<int> f2 = std::aysnc(std::launch:async, [](){cout << 8 << endl;});
f2.wait();

std::future<int> future = std::async(std::launch::async, [](){
            std::this_thread::sleep_for(std::chrono::seconds(3));
            return 8;
        });
std::cout << "waiting...\n";
std::future_status status;
do {
    status = future.wait_for(std::chrono::seconds(3));
    if(status == std::future_status::deferred)
        std::cout << "deferred\n";
    else if(status == std::future_status::timeout)
        /*TODO*/
    else if(status == std::future_status::ready)
        /*TODO*/
} while(status != std::future_status::ready)
std::cout << future.get() << std::endl;

应该用std::async代替线程的创建


有一次在百度面试过程中被问到future、promise的东西,但是没答上来,之后对这个知识点复习了下。

c++11的future提供了另外一种独特的方式让我们可以和创建的线程进行沟通。
promise这个类会创建空间来保存线程的返回值,然后主线程再去读这个空间就可以。

future实际上是可以理解为指向任务结果的指针,这样子的话那么promise就可以理解为是future和data的封装。

packaged_task是将函数对象和future封装在一起的

async可以同步/异步创建线程,函数的返回值是std::future的,那么就可以得到该线程的运行结果了。

#include 
#include 
#include 

/* This code is for future,promise,packaged_task and async
 */
int main()
{
    std::promise<int> prom;
    std::thread([](std::promise<int> &p){ std::this_thread::sleep_for(std::chrono::seconds(1));
                p.set_value_at_thread_exit(10);}, std::ref(prom)).detach();
    std::future<int> f1 = prom.get_future();
    std::cout << f1.get() << std::endl;

    std::cout << "packaged_task: " << std::endl;
    std::packaged_task<int(int)> task(
                          [](int x)x->int{
                          std::this_thread::sleep_for(std::chrono::seconds(1));return x+2;});
    std::future<int> f2 = task.get_future();
    std::thread(std::move(task), 2).detach();
    std::cout << f2.get() << std::endl;

    std::cout << "async :" << std::endl;
    std::future<int> f3 = std::async(std::launch::async, []()->int{
            std::this_thread::sleep_for(std::chrono::seconds(1)); return 8;});
    std::future_status status;
    while(1)
    {
       status = f3.wait_for(std::chrono::seconds(1));
       if(status == std::future_status::ready)
           break;
    }

    std::cout << f3.get() << std::endl;
    return 0;
}

你可能感兴趣的:(C++)