C++中的多线程编程...从哪里开始?

14
我想开始学习C++中的多线程编程,同时我也在学习Java中的多线程。在Java中,如果我编写一个使用多线程的程序,则可以在任何地方运行。然而,在C++中,多线程是否依赖于特定于平台的API?如果是这样,那么似乎会影响可移植性。
如何在C++中实现多线程而不会导致可移植性问题?boost的thread库是一个好的解决方案吗?
顺便说一下,如何将多线程作为库实现?这不是编译器必须完成的事情吗?

1
作为一种警告,你将不得不在C++中更多地考虑线程安全。不能仅仅通过在类方法中添加同步关键字来使它们线程安全。通常需要使用诸如互斥锁或其他形式的临界区、原子操作等工具。但是,如果正确使用,您将能够编写非常高效的多线程代码。您甚至可以编写自己的内存分配器,带有每个线程的内存池,但这比Java更低级别,更难以正确编写。 - stinky472
(+1) @stinky472:这正是我想学习C++和Java的多线程的原因。我感觉Java通常很适合初步了解许多主题,但仅仅停留在Java不会让程序员接触到一些非常重要的概念。因此,在学习Java中的多线程的同时,我也希望学习C++中的多线程,以确保我学到了所有应该学习的东西。 - Cam
10个回答

15
如果您还没有支持C++0x的编译器(例如,Visual Studio C++ 2010),请使用boost线程。(除非您使用已经支持线程的框架,否则您不会问这个问题。)在全新的C++中,这些boost线程实际上成为了标准。在此之前,C++本身是不支持线程的。
如果你想学习并行编程的其他方面,TBB Threading Building Blocks也可能对你有所帮助。
关于Qt:如果你只需要线程支持,那么它就过度了。从编译到结果的往返时间非常慢。它设计得非常好,但不像来自boost的C++0x线程那样是官方标准。因此,我不会把它作为第一选择。

谢谢。所有的答案都非常有帮助,但我认为这个最具信息价值。 - Cam

4
在C++中,线程是特定于平台的。但是,许多线程库封装了在各种平台上使用线程的细节,提供了一个统一的API,使您可以编写线程应用程序,而无需担心特定于平台的细节。
Boost线程库是一个非常好的解决方案。
我也建议检查ACE

4

让我们倒过来开始:

如何在库中实现线程?

在(纯)C++ 中无法做到,这需要语言支持(编译器只是一种实现)。

目前有两种方式:

  • 某些部件使用汇编代码(例如 pthread 库)
  • 其他部分则使用特定的编译器指令(取决于编译器和平台)

两者都很脆弱,并且需要大量的工作才能实现可移植性。基本上就意味着在代码中有很多 #ifdef 部分,用于测试编译器和目标架构的支持情况以及测试是否支持某些指令等等...

这就是为什么认为有必要在 C++0x 中添加线程支持。

如何进行多线程编程?

即使在选择库之前,您也应该选择一种方法。有两种编程多线程应用程序的方法(可以组合使用):

  • 通过共享来通信:这意味着使用互斥锁、原子操作等... 您可以在 Linux 平台上使用 pthread,但我建议使用 Boost.Thread(以及其他)来实现可移植性。
  • 通过通信来共享:这是一种更加新颖的方法,适用于分布式计算,源自函数式语言。这意味着从一个线程向另一个线程传递消息,而不共享任何资源。您可以使用FastFlow 或 Intel 的 Thread Building BlocksTBB

您可以将两者合并,但最好不要这样做。个人认为 FastFlow 的描述非常棒:它鼓励无锁编程。此外,第二种方法的主要优点是它更适合多进程编程,并且可扩展到分布式环境。

首先,我建议专注于其中一种并构建一些应用程序。当您感到舒适时,可以尝试另一种方法,但要准备重新开始,因为它们有很大的不同。


编译器不支持线程,它由操作系统确定。例如,在纯C ++中实现它的方法是包含pthread头文件,使用其函数并链接到其库。编译器本身对pthread一无所知。 - Gianni
嗯,我想说使用基于汇编的库并不是纯粹使用 C++ ;) 不过我会纠正关于编译器的那一点,我指的是语言。 - Matthieu M.
@Gianni 编译器仍然需要意识到存在多个线程的可能性,以便不应用在单个线程中安全的优化或重新排序,在多个线程中则不安全。 - Logan Capaldo
@Logan 我可能错了,但我认为编译器(实际上是gcc)并不知道这一点,所以它有原子操作和内存屏障,程序员必须自己添加。 - Gianni
@Gianni 原子操作和内存栅栏正是你需要通过扩展语言来为编译器提供这些信息的内容。确实,线程支持在某种程度上取决于编译器。 - Logan Capaldo
显示剩余4条评论

2
//This program explains how pthread works, here 5 thread are trying to update a global variable simultaneously but with locking synchronization in maintained
#include<iostream>
#include<pthread.h>
using namespace std ;

#define MAX_NO_THREAD 5

    int global_sum = 0 ;
    pthread_mutex_t lock ;    //Declared global lock mutex object

void *print_fun(void *arg)
{
    cout<<"\nThread id : "<<(int)arg;
    pthread_mutex_lock(&lock) ; //aquiring lock on piece of code
    for ( int j=0; j<100000000; j++)
    {
        global_sum++ ;
    }
    pthread_mutex_unlock(&lock) ; //reomving lock on peice of code
    cout<<"\nGlobal Sum : "<<global_sum ;
}

int main()
{
    int i = 0 ;
    pthread_t threads_obj[MAX_NO_THREAD] ; //Initializing object array for thread
    pthread_mutex_init(&lock, NULL) ; //Initalinzing lock object for thread
    int st ;
    for ( i=0; i<5; i++)
    {
        pthread_create(&threads_obj[i], NULL, *print_fun, (void *)i) ;//Initializing threads calling function print_fun
        pthread_join(threads_obj[i], 0) ; //Forcing main thread to main until these thread complete
    }
    pthread_mutex_destroy(&lock) ; //Destroying lock object
}



//compile this program using -lpthread option with g++
//g++ thread.cc -lpthread

1

还可以查看Qt


1
提供一个不同于 Boost 的建议,我使用 Pthreads(或在 Windows 上使用 Pthreads-Win32)。它是一个非常自助的裸骨库,但为您提供了所需的一切,没有多余的功能。与 Boost 相比,它非常轻量级,您可以很容易地找到 C++ 封装以提供更高级别的抽象。

来自boost的线程库是一个模板“仅头文件”库。它不会创建任何大的开销。好吧,所需的一堆文件可能很大,但在最终结果中,您只会有来自模板实例化的几个字节。 - jdehaan
@jdehaan:你能详细解释一下“模板”头文件库的含义吗? - Cam
3
我必须承认,“仅头文件”这个概念也让我感到相当惊讶。这个文件名:libboost_thread-vc100-mt-gd-1_43.lib 并不像是一个头文件。 - Matthieu M.
哦,我想我可能在 shared_ptr、unique_ptr 和 weak_ptr 这些头文件中搞砸了(@incrediman:不需要库或 DLL,只需 *.hpp 文件)。抱歉,你是对的,那就不是那么小了……该 DLL 还带有线程和互斥类以及许多其他内容。 - jdehaan
这里有一个很好的帖子,讨论了专家们关于使用Boost Threads的部分是否应该是仅头文件的优缺点:http://old.nabble.com/-threads--making-parts-of-Boost.Threads-header-only-td22926099.html - jdehaan

1

你还可以考虑使用 OpenMP http://openmp.org。许多编译器都支持它,包括 MS、GCC/G++ 和 Intel。尽管你没有对线程的显式控制,但它更高级抽象的并行性有时更有效(无论是在编码时间还是运行时),而且代码更易于理解。如果你在做 GUI 工作,这对你帮助不大,但对于可扩展计算来说,它值得一看。


1
Boost Threading Library 可能是 C++ 开始编写多线程应用程序的最佳选择。它提供了线程构造函数,以及编写真正工作的多线程应用程序所需的所有互斥锁和控制对象。

1

0

如果您出于兴趣来提高不同编程模型和语言技能的知识,那么Boost库是一个很好的选择。然而,我认为在实际构建任何生产应用程序时使用多线程C++需要仔细考虑。

C++有时候已经具有挑战性,要想正确无误地完成任务,就不要增加共享内存多线程的相当复杂性。即使是最有经验的程序员也会同意,多线程程序极其难以理解和正确实现。即使是最简单的程序,在多线程情况下也很快变得难以测试和调试。

命令式语言(如C++、Java或C#)通常是尝试构建多线程应用程序的最不可接近的方式,因为它们具有可变变量、共享内存和锁定/信号原语。通常有完全可以胜任大多数用户空间(而非内核或嵌入式)应用程序问题的单线程实现选项,包括在多核机器上。

如果您真的想要构建可靠的“多线程”应用程序,我建议您查看像Erlang、Haskell、F#或Clojure这样的函数式语言。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接