• C++11多线程教学


    转自: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》,这是一本好书。

  • 相关阅读:
    经典的ajax遍历循环
    fastadmin别名关联表与js下划线冲突问题解决:with里的别名,不要用驼峰,用shippingtype
    thinkphp 临时关闭布局,ajax只输出主题部分
    linux php5.6 链接sql server
    ecstore导入文件开发问题解决 死循环+不兼容mac换行解决
    thinkphp 二级目录安装
    解决crontab执行时间与系统时间不一致的问题
    电阻性能检测的二种方法(转载)
    短路的原因与危害有哪些
    潮湿引发的电路板常见故障(转载)
  • 原文地址:https://www.cnblogs.com/zhengfa-af/p/8308920.html
Copyright © 2020-2023  润新知