STL线程库简介

在std::thread库中,一个线程用的是一个thread对象表示,当创建一个thread对象时即创建一个线程,一个简单的示例如下:

    #include <iostream>
    #include <thread>
    using namespace std;

    void thread_entry(const char* arg)
    {
        cout << "thread "<< this_thread::get_id() << " created: " << arg << endl;
    }

    int main()
    { 
        thread thrd(thread_entry, "hello world");
        thrd.join();
        return 0;
    }

这里我通过thread对象创建了一个线程,并调用join函数等待线程结束。

std::this_thread名字空间

this_thread::get_id()函数用以获取当前线程的tid,std::this_thread名字空间提供了如下函数以管理当前线程:

  • yield

  • get_id

  • sleep_for

  • sleep_until

基本上从名字里就可以猜出它们的功能了。以其中的sleep_for函数为例,它提供了一个跨平台的sleep功能,再也不用自己封装了:

    std::chrono::milliseconds dura(2000);
    std::this_thread::sleep_for(dura);

PS:在gcc中使用这个函数时,需要再编译的时候加-D_GLIBCXX_USE_NANOSLEEP选项,否则报语法错误,具体原因可以参看这篇文章

Linux平台的运行错误

上述代码在Windows平台运行良好,但在Linux上运行的时候发现如下错误:

    tianfang > run
    terminate called after throwing an instance of 'std::system_error'
        what(): Operation not permitted
    Aborted
    tianfang >

然后在StackOverFlow上找到了答案:在链接的时候要加 –lpthread 选项。这个应该算个bug了。

删除Thread对象

我最初以为当thread对象删除时会自动杀掉线程,运行时却发现:thread对象删除时,如果没有调用join或detach,就会报异常。为了演示这一过程,首先我们把main函数改成如下所示:

    int main()
    { 
        thread thrd(thread_entry, "hello world");
        //thrd.join();
        return 0;
    }

运行该代码时,就会发现如下错误:

    tianfang > run
    terminate called without an active exception
    Aborted
    tianfang >

也就是说,thread对象并不会自动管理线程结束,需要手动控制。常见的控制手段有两个,join和detach。join已经介绍过,用于等待线程结束,而detach的功能是托管线程,线程仍然继续运行至结束,但不再受到thread对象控制。

对线程编程模型比较熟悉的人可能会发现:它并没有提供一个强制终止线程的选项。在boost的this_thread名字空间下其实是提供了终止线程的函数的,但是并没有纳入stl中,可见标准委员会也是不建议强制终止这种不健壮的做法。

互斥和同步

互斥体

stl中对mutex划分得很细,按是否递归、是否超时分为四个对象:

  • mutex

  • timed_mutex

  • recursive_mutex

  • recursive_timed_mutex

这四个对象的操作函数大体上都是如下几个:

  • lock    获取锁

  • trylock    尝试获取锁

  • unlock    释放锁

  • try_lock_for    在一定时间范围内尝试获取锁(有超时功能的mutex才能用)

  • try_lock_until    尝试获取锁到某个时间点位置(有超时功能的mutex才能用)

除了直接使用这几个类外,也可以使用lock_guar、unique_lock之类的的封装类。

另外,stl也提供了try_lock和lock的泛型方法实现批量获取锁定,这里就不多介绍了。

条件变量

stl中对条件变量封装的是condition_variable类,它的基本使用方式和系统api差不多,如下是一个生产者/消费者的例子:

    #include <condition_variable>
    #include <mutex>
    #include <thread>
    #include <iostream>
    #include <queue>
    #include <chrono>
    using namespace std;

    int main()
    {
        queue<int> buffer;
        mutex m;
        condition_variable cond_var;
        int num = 0;

        thread producer([&]() 
        {
            while (true)
            {
                this_thread::sleep_for(chrono::seconds(1));

                unique_lock<std::mutex> lock(m);

                num++;
                std::cout << "producing " << num << '\n';
                buffer.push(num);

                cond_var.notify_one();
            } 
        }); 

        thread consumer([&]() 
        {
            while (true) 
            {
                unique_lock<std::mutex> lock(m);

                if(buffer.empty())
                    cond_var.wait(lock);

                std::cout << "consuming " << buffer.front() << '\n';
                buffer.pop();
            } 
        }); 

        producer.join();
        consumer.join();
    }

条件变量还有其它几个封装,这里就不多介绍了。

其它

其它几个同步互斥的类,如栅栏、读写锁等并没有纳入STL,如果要使用它们,可以直接使用boost库。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值