转自:http://www.cnblogs.com/lidabo/p/3908705.html

本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads。

在之前的教学中,我展示了一些最新进的C++11语言内容:

  • 1. 正则表达式(http://solarianprogrammer.com/2011/10/12/cpp-11-regex-tutorial/)
  • 2. raw string(http://solarianprogrammer.com/2011/10/16/cpp-11-raw-strings-literals-tutorial/)
  • 3. lambda(http://solarianprogrammer.com/2011/11/01/cpp-11-lambda-tutorial/)

也许支持多线程是C++语言最大的变化之一。此前,C++只能利用操作系统的功能(Unix族系统使用pthreads库),或是例如OpenMP和MPI这些代码库,来实现多核计算的目标。

本教程意图让你在使用C++11线程上起个头,而不是只把语言标准在这里繁复地罗列出来。

创建和启动一条C++线程就像在C++源码中添加线程头文件那么简便。我们来看看如何创建一个简单的带线程的HelloWorld:

#include《iostream》

#include《thread》

//This function will be called from a thread

//该函数将在一条线程中得到调用

void call_from_thread() {

std::cout << "Hello, World" << std::endl;

}

int main() {

//Launch a thread

//启动一条线程

std::thread t1(call_from_thread);

//Join the thread with the main thread

//和主线程协同

t1.join();

return 0;

}

在Linux系统中,上列代码可采用g++编译:

g++ -std=c++0x -pthread file_name.cpp

在安装有Xcode4.x的麦金系统上,可用clang++编译上述代码:

clang++ -std=c++0x -stdlib=libc++ file_name.cpp

视窗系统上,可以利用付费代码库,just::thread,来编译多线程代码。但是很不走运,他们没有提供代码库的试用版,我做不了测试。

在真实世界的应用程序中,函数“call_from_thread”相对主函数而言,独立进行一些运算工作。在上述代码中,主函数创建一条线程,并在t1.join()处等待t1线程运行结束。如果你在编码中忘记考虑等待一条线程结束运行,主线程有可能抢先结束它自己的运行状态,整个程序在退出的时候,将杀死先前创建的线程,不管函数“call_from_thread”有没有执行完。

上面的代码比使用POSIX线程的等价代码,相对来说简洁一些。请看使用POSIX线程的等价代码:

//This function will be called from a thread

void *call_from_thread(void *) {

std::cout << "Launched by thread" << std::endl;

return NULL;

}

int main() {

pthread_t t;

//Launch a thread

pthread_create(&t, NULL, call_from_thread, NULL);

//Join the thread with the main thread

pthread_join(t, NULL);

return 0;

}

我们通常希望一次启动多个线程,来并行工作。为此,我们可以创建线程组,而不是在先前的举例中那样创建一条线程。下面的例子中,主函数创建十条为一组的线程,并且等待这些线程完成他们的任务(在github代码库中也包含这个例子的POSIX版本):

...

static const int num_threads = 10;

...

int main() {

std::thread t[num_threads];

//Launch a group of threads 启动一组线程

for (int i = 0; i < num_threads; ++i) {

t[i] = std::thread(call_from_thread);

}

std::cout << "Launched from the mainn";

//Join the threads with the main thread

for (int i = 0; i < num_threads; ++i) {

t[i].join();

}

return 0;

}

记住,主函数也是一条线程,通常叫做主线程,所以上面的代码实际上有11条线程在运行。在启动这些线程组之后,线程组和主函数进行协同(join)之前,允许我们在主线程中做些其他的事情,在教程的结尾部分,我们将会用一个图像处理的例子来说明之。

在线程中使用带有形参的函数,是怎么一回事呢?C++11允许我们在线程的调用中,附带上所需的任意参数。为了举例说明,我们可以修改上面的代码,以接受一个整型参数(在github代码库中也包含这个例子的POSIX版本):

static const int num_threads = 10;

//This function will be called from a thread

void call_from_thread(int tid) {

std::cout << "Launched by thread " << tid << std::endl;

}

int main() {

std::thread t[num_threads];

//Launch a group of threads

for (int i = 0; i < num_threads; ++i) {

t[i] = std::thread(call_from_thread, i);

}

std::cout << "Launched from the mainn";

//Join the threads with the main thread

for (int i = 0; i < num_threads; ++i) {

t[i].join();

}

return 0;

}

在我的系统上,上面代码的执行结果是:

Sol$ ./a.out

Launched by thread 0

Launched by thread 1

Launched by thread 2

Launched from the main

Launched by thread 3

Launched by thread 5

Launched by thread 6

Launched by thread 7

Launched by thread Launched by thread 4

8L

aunched by thread 9

Sol$

能看到上面的结果中,程序一旦创建一条线程,其运行存在先后秩序不确定的现象。程序员的任务就是要确保这组线程在访问公共数据时不要出现阻塞。最后几行,所显示的错乱输出,表明8号线程启动的时候,4号线程还没有完成在stdout上的写操作。事实上假定在你自己的机器上运行上面的代码,将会获得全然不同的结果,甚至是会输出些混乱的字符。原因在于,程序内的11条线程都在竞争性地使用stdout这个公共资源(案:Race Conditions)。

要避免上面的问题,可以在代码中使用拦截器(barriers),如std:mutex,以同步(synchronize)的方式来使得一群线程访问公共资源,或者,如果可行的话,为线程们预留下私用的数据结构,避免使用公共资源。我们在以后的教学中,还会讲到线程同步问题,包括使用原子操作类型(atomic types)和互斥体(mutex)。

从原理上讲,编写更加复杂的并行代码所需的概念,我们已经在上面的代码中都谈到了。

如果有兴趣学习新的C++11语法,我建议阅读《Professional C++》,或《C ++ Primer  Plus》。C++11多线程主题方面,建议阅读《C++ Concurrency in Action》,这是一本好书。

C++11多线程教学的更多相关文章

  1. C++11多线程教学(二)

    C++11多线程教学II 从我最近发布的C++11线程教学文章里,我们已经知道C++11线程写法与POSIX的pthreads写法相比,更为简洁.只需很少几个简单概念,我们就能搭建相当复杂的处理图片程 ...

  2. C++11多线程教学(一)

    本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...

  3. C++11多线程教学II

    从我最近发布的C++11线程教学文章里,我们已经知道C++11线程写法与POSIX的pthreads写法相比,更为简洁.只需很少几个简单概念,我们就能搭建相当复杂的处理图片程序,但是我们回避了线程同步 ...

  4. c++ 11 多线程教学(1)

    本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...

  5. C++11 多线程 教学(2)

      C++11开始支持多线程编程,之前多线程编程都需要系统的支持,在不同的系统下创建线程需要不同的API如pthread_create(),Createthread(),beginthread()等, ...

  6. 【转】C++ 11 并发指南一(C++ 11 多线程初探)

    引言 C++ 11自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些C++ 11的新特性,算是记录一下自己学到的东西吧,和大家共勉. 相信Linux程序员都用过Pthrea ...

  7. C++11 并发指南一(C++11 多线程初探)

    引言 C++11 自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些 C++11 的新特性,今后几篇博客我都会写一些关于 C++11 的特性,算是记录一下自己学到的东西吧, ...

  8. C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)

    要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...

  9. C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)

    前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...

随机推荐

  1. LNMP一键安装包phpMyAdmin无法正常登录,提示:您的Session已过期,请再次登录。

    找到文件: /usr/local/php/etc/php.ini 搜索: session.auto_start = 0 修改为 session.auto_start = 1 保存即可!

  2. MQTT的学习研究(六) MQTT moquette 的 Blocking API 订阅消息客户端使用

    * 使用 Java 为 MQ Telemetry Transport 创建订户 * 在此任务中,您将遵循教程来创建订户应用程序.订户将针对主题创建预订并接收该预订的发布. * 提供了一个示例订户应用程 ...

  3. MQTT的学习研究(三)moquette-mqtt 的使用之mqtt服务发布主题信息

    接着上一篇的moquette-mqtt 的使用之broker启动之后,我们需要启动moquette-mqtt 的服务端发布消息. 在moquette-mqtt 的mqtt-client中三种方式实现发 ...

  4. getOwnPropertyNames() & keys()

    1.getOwnPropertyNames方法可以获得对象的所有属性名,并储存于一个数组当中. keys方法只能获取可遍历的属性名并储存于数组. 2.在完成notepad模块模拟的过程中使用了getO ...

  5. ios开发 点击文本(TextField)输入的时候向上推以及输入之后恢复的动画

    1.添加委托UITextFieldDelegate 2. -(BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resi ...

  6. 阿里云搭建SVN服务器

    1:安装svn apt-get install subversion 2. 开启svn服务器 svnserve -d 检查是否开启:ps aux | grep svnserve 若出现如下内容: wk ...

  7. WebConfig配置详解大全

    <?xml version="1.0"?> <!--注意: 除了手动编辑此文件以外,您还可以使用 Web 管理工具来配置应用程序的设置.可以使用 Visual S ...

  8. opencv学习笔记——FileStorage类的数据存取操作

    OpenCV的许多应用都需要使用数据的存储于读取,例如经过3D校准后的相机,需要存储校准结果矩阵,以方便下次调用该数据:基于机器学习的应用,同样需要将学习得到的参数保存等.OpenCV通过XML/YA ...

  9. Meaning of “const” last in a C++ method declaration?

    函数尾部的const是什么意思? 1 Answer by Jnick Bernnet A "const function", denoted with the keyword co ...

  10. 使用log4net做应用程序全局日志记录保存在数据库中

    几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管理员可能需要有一套强大的日志系统来诊断和修复配置上的问题.经验表明,日志记录往往 ...