UP | HOME

C++11 下的线程编程

目录

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
...

而这正是我想要的结果。

参考

版权所有 ©2015: Exaos Lee | Date: [2014-12-19 五] | Generated by Emacs 24.4.1 (Org mode 8.3.2), Validate, 88x31.png

comments powered by Disqus