本文摘自作者盖伊·凯伦斯(Guy Kerens). 预期本文将翻译三章,主要涉及pthreads,互斥(锁)和条件变量的基础知识,其一是因为这已经可以指导读者入门,另一则是因为我在下班后进行翻译,真的很紧急. 翻译: 张小川,请保留原作者转载
本文旨在使您熟悉使用POSIX的多线程编程,并向您展示如何在“真实”编程中使用其功能. 它解释了库定义的各种工具,展示了如何使用它们,并提供了使用它们解决编程问题的示例. 本文假定读者具有并行编程概念的一些基本理论知识. 没有这些知识背景的读者可能会发现这些概念难以理解. 我将准备一份单独的文档,向只熟悉“串行”编程的读者解释这些理论背景.
我将假定熟悉异步编程模型(例如在窗口环境中使用的(X,Motif))的读者将更容易理解多线程编程的概念.
在谈到POSIX线程时,不可避免的问题是“应该使用哪个版本的POSIX线程标准?”由于此线程标准已在几年内进行了修改,因此您会发现该标准的不同版本的实现存在不同的功能集,不同的默认值,不同的差异. 由于此评论是在Linux系统上编写的,并且内核LinuxThreads库版本为v0.5,因此使用其他系统或pthread库的其他版本的程序员应参阅相应的系统手册,以防止不兼容. 而且,由于某些示例使用系统功能,因此它们无法在用户级线程库上运行(有关更多信息,请参阅我们的并行编程理论教程). 说到这些,我将尝试在其他系统(想到了Solaris 2.5)上检查这些示例,以使它们更“跨平台”.
线程是一个“半进程”,它具有自己的堆栈并执行给定的代码. 与进程不同posix 线程池,线程之间的内存通常是共享的(不同的进程通常具有不同的存储区域). 线程组是在同一进程中执行的线程的集合. 它们共享内存,因此可以访问相同的局部变量,相同的堆存储,相同的文件描述符,等等. 所有这些线程都是并行执行的(即使用时间片或在多核处理器上真正实现并行性).
与串行程序相比,线程组的优势在于可以并行执行多个操作,因此事件到达时可以立即进行处理(例如,如果一个线程处理用户界面,而另一个线程处理访问,那么可以在仍然响应用户输入的情况下执行大量用户查询.
线程组相对于进程组的优势在于,线程之间的上下文切换比进程之间的上下文切换要快得多(上下文切换是指系统从正在运行的线程或进程切换到另一个线程或进程). 而且,线程间通信通常比进程间通信更快,更容易实现.
另一方面,由于一个线程组使用相同的存储空间,因此,如果一个线程导致内存中的数据崩溃,那么其他线程也将受到影响. 但是在此过程中,操作系统通常会相互保护进程,因此,如果一个进程崩溃了其存储空间,则其他进程不会受到影响. 使用进程的另一个好处是,它可以在不同的计算机上运行,而线程(通常)仅在一台计算机上运行.
当多线程程序开始执行时,它正在运行一个线程,该线程是执行main()函数的线程. 这已经是一个完整的线程,并且具有自己的线程ID. 要创建新线程,应调用pthread_create()函数. 以下是使用它的示例:
/*
* pthread_create.c
*/
#include
#include
void *do_loop(void *data)
{
int i;
int j;
int me = *((int*)data);
for(i = 0; i < 10; i ++)
{
for(j = 0; j < 5000000; j ++)
{
;//just for delay
}
printf("'%d' - got '%d'\n", me, i );
}
/*terminate the thread*/
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
int thread_id;
pthread_t p_thrd;
int a = 1;
int b = 2;
thread_id = pthread_create(&p_thrd, NULL, do_loop, (void *)&a);
//run the fun in the main thread
do_loop((void *)&b);
return 0;
}
有关该程序的几点注意事项:
请注意posix 线程池,main函数也是一个线程,因此它将使用其创建的线程执行do_loop()函数; pthread_create()函数需要四个参数. 函数pthread_create()使用第一个参数来提供有关线程的信息(即线程标识符). 第二个参数用于指定新线程的属性. 在我们的示例中,我们将NULL指针传递给pthread_create()以使用默认属性. 第三个参数是线程执行程序的名称. 第四个参数是传递给函数(由线程执行的函数)的参数. 请注意,ANSI-C语法不需要将映射到void *,但是在此更加清楚. 该函数中的循环延迟仅用于演示线程是并行执行的. 如果您的CPU运行速度很快,请使用较大的延迟;然后您将看到一个线程的所有打印结果在另一个线程之前. pthread_exit()函数的调用导致线程退出并释放该线程占用的所有资源. 不必程的最外层函数的末尾调用此函数,因为当它返回时,线程将自动退出. 当我们想程中间结束时使用此函数.
为了使用gcc编译多线程程序,我们需要链接到pthread库. 假设您已经在系统上安装了该库,下面显示了如何编译我们的第一个程序
gcc pthread_create.c -o pthread_create -lpthread
请注意,在此评估的下一个程序中,您可能需要在编译行中添加-D_GNU_SOURCE标志,以使源代码得以编译.
参考:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-192973-1.html