zoukankan      html  css  js  c++  java
  • STL线程库简介

    STL线程库的前身是boost::thread,在C++ 11标准化后便正式归纳入了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函数等待线程结束。thead对象的构造函数中是可以传入参数的,非常方便。

    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上找到了答案:在链接的时候要加 –pthread 选项。这个应该算个bug了。

    删除Thread对象

    我最初以为当thread对象删除时会自动杀掉线程,运行时却发现:thread对象删除时,如果没有调用join或attach,就会报异常。为了演示这一过程,首先我们把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之类的的封装类,它的功能上类似C#的lock关键字(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库。

  • 相关阅读:
    iOS进阶二-KVC
    iOS进阶一OC对象的本质
    2019-01-19
    2019-01-12
    2019
    2018-12-23 随笔
    2018-12-18 随笔
    2018-12-10
    2018-12-01
    2018.11.23 随笔
  • 原文地址:https://www.cnblogs.com/TianFang/p/2878519.html
Copyright © 2011-2022 走看看