C++11多线程

线程

例子

程序需要从main函数开始,同样线程也是从某个函数开始的(这个函数下文称为线程函数)。和pthread_create一样,C++11提供的线程类std::thread,在创建类变量的时候就产生一个线程,因此需要在std::thread的构造函数中传入线程函数作为参数。得益于C++11支持可变参数模板和完美转发,如果线程函数拥有参数,那么可以十分自然地通过std::thread的构造函数传递。


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


void threadFunc(std::string &str, int a)
{
    str = "change by threadFunc";
    a = 13;
}

int main()
{
    std::string str("main");
    int a = 9;
    std::thread th(threadFunc, std::ref(str), a);

    th.join();

    std::cout<<"str = " << str << std::endl;
    std::cout<<"a = " << a << std::endl;

    return 0;
}

上面例子的输出为:

str = change by threadFunc 
a = 9

线程函数不仅支持普通函数,还可以是类的成员函数和lambda表达式。如下:

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


class ThreadObject
{
public:

    void threadFunc(const std::string &str, double d)
    {
        std::cout << "ThreadObject::threadFunc: str = " << str << "\t d = " << d << std::endl;
    }


    void operator () (const std::string &str, int i)
    {
        std::cout << "TheadObject::operator (): str = " << str << "\t i = " << i << std::endl;
    }

};

int main()
{
    int score = 99;
    std::thread th1([&score]() {
        std::cout << "score = " << score << std::endl; });

    th1.join();

    ThreadObject to;
    std::thread th2(&ThreadObject::threadFunc, &to, "xiaoming", 98);
    th2.join();

    std::thread th3(std::ref(to), "xiaohua", 97);
    th3.join();

    return 0;
}

上面例子输出为:

score = 99
ThreadObject::threadFunc: str = xiaoming    d = 98
TheadObject::operator (): str = xiaohua     i = 97

管理线程

在上面的例子中已经看到,std::thread在构造函数中创建线程。根据RAII基本法,在构造函数申请资源,并且在析构函数中释放资源。 但std::thread的析构函数能释放线程资源吗?线程和std::thread是两个不同的实体。线程是操作系统层面的,而std::thread变量则是C++层面的,两者有不同的生命周期。从代码层面来说,std::thread变量在主函数中被析构了,可能线程函数还没运行完毕。如果std::thread变量在线程运行完毕前就析构了,线程资源交由谁管理?

容易想到的一个解决方案是保证std::thread变量的生命周期大于线程本身。上面的例子就是这样做的:主线程通过调用join()函数,等待线程运行完毕。主线程调用join函数后会进入等待状态,直至次线程运行完毕后,主线程才从join函数返回。不同于pthread_join可以获取线程函数的返回值,std::thread的join函数并不能获取线程函数的返回值

“启动一个线程,然后暂停当前线程”,这种处理方式想想就觉得不对(当然如果同时启动多个线程,然后才一个个调用join还是可取的)。为此,std::thread还提供另外一个函数detach。调用detach函数后,std::thread变量会和其关联的线程失去关联,由C++运行库释放相关的线程资源。

join函数或者detach函数都必须在std::thread变量析构之前调用。否则std::thread的析构函数将调用std::terminate()终止整个进程。如果std::thread变量在析构之前,线程就已经执行完毕了呢?一样会挂!

std::mutex

C++ 11提供了4中不同的锁,这里只介绍std::mutex。std::mutex只有几个成员函数,我们这里只需关注lock和unlock函数即可。加锁解锁相当简单,看下面例子。

#include<thread>
#include<iostream>
#include<mutex>
#include<vector>
#include<iterator>


std::mutex g_mutex;


void doThreadFunc(int n, char c)
{
    g_mutex.lock();

    std::vector<int> vec(n, c);
    std::copy(vec.begin(), vec.end(), std::ostream_iterator<char>(std::cout, ""));
    std::cout << std::endl;

    g_mutex.unlock();
}


template<typename ... Args >
void threadFunc(Args&& ... args)
{
    try
    {
        doThreadFunc(std::forward<Args>(args)...);
    }
    catch (...)
    {
    }
}




int main()
{
    std::thread th1([] {threadFunc(10, '*'); });//这么蹩脚的写法是因为threadFunc需要先实例化
    std::thread th2([] {threadFunc(5, '#'); });

    th1.join();
   
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值