UP | HOME

C++11 下的线程编程

Table of Contents

C++11 中正式引入了标准类 std::thread, 也就是说,你编写使用线程的程序时不再需要使用 C 下面的 pthread 等 API, 可以直接用 C++11 标准的库来实现线程了。

本笔记的主要运行平台为 Debian Linux 7.1 (wheezy), gcc 4.7.2. 使用 GCC 编译笔记中的代码,需要注意:

GCC 各版本对 C++11 特性的支持情况参见: http://gcc.gnu.org/projects/cxx0x.html

用线程运行一个简单的函数

直接使用头文件 <thread> 中包含的标准类 std::thread, 示例如下:

#include <thread>
                        #include <iostream>

                        void my_thread_func()
                        {
                        std::cout<<"hello"<<std::endl;
                        }

                        int main()
                        {
                        std::thread t(my_thread_func);
                        }
                        

编译:

                        g++ -std=c++11 -pthread a.cpp

                    

但执行后无任何输出。如果想获得线程的执行结果,需要将其连接 (joining) 起来,因此,上述代码需要在 std::thread t(my_thread_func); 声明之后添加一句:

                        t.join();

                    

要想让线程在指定地方结束,必须等待它完成。

异步执行 (async) 一个线程

假如想让一个函数每隔 1 秒钟将全局计数器增加一个计数,又不想让这个函数影响到主线程的执行。那么可以用 std::async 来实现。例如:

#include <future>
                        #include <chrono>
                        #include <iostream>

                        static int fCount;

                        void called_from_async() {
                        fCount++;
                        std::cout << "Async call: " << fCount << ", " << asString(tp) << std::endl;
                        std::this_thread::sleep_for(std::chrono::seconds(1));
                        called_from_async();
                        }

                        int main() {
                        fCount = 0;

                        // called_from_async launched in a separate thread if possible
                        std::future<void> result(std::async(called_from_async));

                        for(int i=0; i<20; i++) {
                        std::cout << "Message from main: " << i << std::endl;
                        std::this_thread::sleep_for(std::chrono::seconds(1));
                        }

                        // Ensure that called_from_async is launched synchronously
                        // if it wasn't already launched
                        result.get();

                        return 0;
                        }
                        

但上述程序中 called_from_async 并不会马上执行,而是等待中间的循环结束后,才开始。这是为什么呢?因为 std:async 的启动策略 (launch policy) 默认设置为 std::launch::any, 意思是说,只有在你明确表示要等待其结果时才开始执行。如果要让函数立刻执行,则需要修改启动策略为 std::launch::async. 同样,如果你确实希望函数只须在 get() 被调用时才执行,则明确指定其启动策略为 std::launch::sync.

完整的程序如下:

#include <future>
                        #include <thread>
                        #include <chrono>
                        #include <iostream>

                        static bool fQuit;
                        static int  fCount;

                        std::string asString (const std::chrono::system_clock::time_point& tp)
                        {
                        // convert to system time:
                        std::time_t t = std::chrono::system_clock::to_time_t(tp);
                        std::string ts = std::ctime(&t);// convert to calendar time
                        ts.resize(ts.size()-1);         // skip trailing newline
                        return ts;
                        }

                        void called_from_async() {
                        fCount++;
                        auto tp = std::chrono::system_clock::now();
                        std::cout << "Async call: " << fCount << ", " << asString(tp) << std::endl;
                        std::this_thread::sleep_for(std::chrono::seconds(1));

                        if(not fQuit) called_from_async();
                        }

                        int main() {
                        fCount = 0;
                        fQuit  = false;

                        // called_from_async launched in a separate thread if possible
                        std::future<void> result(std::async(std::launch::async,called_from_async));

                        for(int i=0; i<20; i++) {
                        std::cout << "Message from main: " << i << std::endl;
                        std::this_thread::sleep_for(std::chrono::seconds(1));
                        }

                        // Ensure that called_from_async is launched synchronously
                        // if it wasn't already launched

                        fQuit = true;
                        result.get();

                        return 0;
                        }
                    

上述程序会在主程序输出消息的中间穿插着异步线程的输出结果,比如:

                    $ ./a.out
                    Message from main: 0
                    Async call: 1, Wed Aug 21 15:27:26 2013
                    Message from main: 1
                    Async call: 2, Wed Aug 21 15:27:27 2013
                    Message from main: 2
                    Async call: 3, Wed Aug 21 15:27:28 2013
                    Message from main: 3
                    Async call: 4, Wed Aug 21 15:27:29 2013
                    Message from main: 4
                    ...
                

而这正是我想要的结果。

参考

88x31.png

版权所有 ©2012-2018: Vivodo Lio | 日期: 2014-12-19 五 00:00

Generated by Emacs 25.3.1 (Org mode 9.1.7), Validate