`
javasee
  • 浏览: 965605 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

POSIX线程(二)

阅读更多


第一个线程程序

有一个完整的与线程相关的库调用集合,其中的大多数名字以pthread_开头。要使用这些库调用,我们必须定义宏_REENTRANT,包含文件pthread.h,并且使用-lpthread来链接线程库。

当设计原始的Unix与POSIX库函数时,假定在任何进程中只有一个执行线程。一个明显的例子就是errno,这个变量用于在调用失败之后获取错误信息。在一个多线程程序中,默认情况下只有一个在线程之间共享的变量。一个线程中的调用可以很容易在另一个线程获取前一个错误代码之前更新这个变量。相似的程序也存在于函数中,例如fputs,通常使用一个全局区域用于缓存输出。

我们需要被称之为可重入的例程。重入代码可以被多次调用,无论是被不同的线程还是被嵌入调用,并且可以正常工作。所以,可重入的代码部分必须使用局部变量,这样对于这个代码的每一个调用都可以获得一份唯一的数据拷贝。

在多线程程序中,我们通过在程序中任何#include代码之前定义_REENTRANT宏来通知编译器我们需要这个特性。这会为我们做三件事情,而我们通常并不需要知道为我们做了什么:

某些函数具有与可重入等同的函数原型。他们通常具有相同的函数名,但是在函数名后添加了_r,例如,gethostbyname就变成了gethostbyname_r。

通常作为宏实现的某些stdio.h中的函数变为了合适的可重入安全函数。

errno.h中的变量errno变成了调用函数,这个函数可以以多线程安全的方式确实真正的errno值。

包含pthread.h文件为我们提供了在我们的代码中所需要的其他定义与原型,类似于用于标准输入与输出例程的stdio.h。最后,我们需要确保我们包含了正确的头文件并且链接实现pthread功能的正确的线程库。我们会在稍后的试验部分了解详细的内容。

pthread_create创建一个新的线程,类似于fork创建一个新的进程。

#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void
*(*start_routine)(void *), void *arg);

这看起来有些复杂,但是实际上很容易使用。第一个参数是一个指向pthread_t的指针。当线程创建后,一个标识就会被写入这个指针所指向的变量。这个标识可以使得我们引用这个线程。下一个参数设置了线程的属性。我们通常并不需要特殊的属性,而且我们可以简单的传递一个NULL作为参数。在本章的后面部分我们会了解如何使用这些属性。最后的两个参数指出了要开始执行的线程函数与要传递给这个函数的参数。

void *(*start_routine)(void *)

上一行简单的表明我们必须传递一个带有void指针作为参数的函数地址,而且这个函数会返回一个指向void的指针。所以我们可以传递任何类型的单个参数,并且返回指向任何类型的指针。使用fork会使得程序在相同的位置使用不同的返回代码继续执行,而使用新线程显式的提供一个新线程开始执行处的函数指针。

如果成功,函数会返回0,如果发生错误则会返回一个错误代码。手册页中有这个函数以及本章中所用的其他函数的错误条件的详细描述。

注:pthread_create,与大多数的pthread_functions类似,是Unix函数中少数几个不遵循-1作为返回错误代码的函数。除非我们非常确定,通常最安全的办法就是在检测错误代码之前查看手册页。

当线程结束时,他会调用pthread_exit函数,类似于进程结束时调用exit。函数结束调用线程,返回一个指向对象的指针。绝不要使用他返回一个指向局部变量的指针,因为当线程返回时,变量将会不再存在,从而会引起一个严重的bug。pthread_exit函数声明如下:

#include <pthread.h>
void pthread_exit(void *retval);

pthread_join是与收集子进程的wait进程函数等同的线程函数。这个函数的声明如下:

#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);

第一个参数是要等待的线程,pthread_create为我们所创建的标识符。第二个参数是一个指向指针的指针,指向由线程返回值的指针。与pthread_create函数类似,这个函数也会在成功时返回零,如果失败则会返回错误代码。

试验--一个简单的线程程序

这个程序创建了另一个线程,演示了他与原始线程共享变量,并且使得新线程向原线程返回一个结果。多线程程序不会比这更简单!下面是thread1.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);

char message[] = "Hello World";

int main()
{
int res;
pthread_t a_thread;
void *thread_result;

res = pthread_create(&a_thread,NULL,thread_function,(void *)message);
if(res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...\n");
res = pthread_join(a_thread,&thread_result);
if(res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}

printf("Thread joined, it returned %s\n",(char *)thread_result);
printf("Message is now %s\n",message);
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg)
{
printf("thread_function is running. Argumen was %s\n",(char *)arg);
sleep(3);
strcpy(message,"Bye");
pthread_exit("Thank you for the CPU time");
}

1 要编译这个程序,首先我们需要确保定义了_REENTRANT。在一些系统上,我们也需要定义_POSIX_C_SOURCE,但是通常来说这个并不是必须的。

2 现在我们必须确保链接了正确的库。依据我们的系统,NPTL默认也许并不是默认的,或者在一些老的系统上,依据内核,也许根本就不可用。幸运的是,本章中的大多数代码都是独立于所用的精确线程库的。在作者的系统,检测标准的/usr/incluce/pthread.h文件显示他名为LinuxThreads,版权日期为1996,所以很明显这是一个旧的库。要得到新的NPTL库,我们需要安装额外的RPM包,来在/usr/include/nptl下提供头文件,并且在/usr/lib/nptl下提供库。

3 在标识与安装了正确的文件以后,我们可以用下面的命令来编译与链接我们的程序了:

$ cc -D_REENTRANT -I/usr/include/nptl thread1.c –o thread1 -L/usr/lib/nptl -lpthread

4 当我们运行这个程序时,我们会得到下面的输出:

$ ./thread1
Waiting for thread to finish...
thread_function is running. Argument was Hello World
Thread joined, it returned Thank you for the CPU time
Message is now Bye!

花一些时间来理解这个程序是很值得的,因为我们将其作为本章中大多数例子的基础。

工作原理

我们声明了一个在线程创建时会调用了函数原型。

void *thread_function(void *arg);

正如pthread_create函数所需要的,他会带有一个指向void的指针作为其唯一参数,并且返回一个指向void的指针。我们会在稍后了介绍函数的定义。

在main函数中,我们声明了一些变量,然后调用pthread_create来启动我们新的线程。

pthread_t a_thread;
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, (void *)message);

我们传递一个pthread_t对象的地址,我们可以使用他在稍后引用这个线程。我们并不希望修改默认的线程属性,所以我们传递一个NULL作为第二个参数。最后两个参数是要调用的函数以及传递给他的参数。

如果调用成功,现在就会运行两个线程。原始线程(main)继续执行并且执行pthread_create之后的代码,并且一个新线程开始执行thread_function代码。

原始线程检测新线程已经开始,然后调用pthread_join。

res = pthread_join(a_thread, &thread_result);

在这里我们传递一个我们等待联合的线程标识以及一个指向结果的指针。这个函数会一直等待,直到另一个在他返回之前结束。然后他会输出线程的返回值以及变量的内容,并退出。

新线程开始执行并且thread_function会输出其参数,休眠一段时间,更新全局变量,然后退出,向主线程返回一个字符串。新线程改写与原始线程访问相同的数组,message。如果我们调用fork而不是pthread_create则不会这样。

分享到:
评论

相关推荐

    windows posix 线程库

    本文将详细讨论“Windows POSIX线程库”及其在Windows环境下实现POSIX线程(pthreads)的功能,以及如何利用该库实现Linux多线程代码在Windows上的运行。 POSIX线程库,通常称为pthreads,是UNIX系统中广泛使用的多...

    posix线程详解.pdf(中文版)

    ### Posix线程详解 #### 1. 线程与进程的概念对比 在计算机科学领域,线程和进程都是实现程序并发执行的基本单位,但它们之间存在显著的区别。线程,尤其是POSIX线程(Portable Operating System Interface ...

    POSIX线程编程指南

    ### POSIX线程编程指南 #### 一、线程创建 ##### 1.1 线程与进程 在计算机科学领域,线程是程序执行的基本单位之一,它比进程更接近于执行体的概念。线程可以与其他同属于一个进程中的线程共享数据,但是每个线程...

    Posix线程(经典)

    Posix线程(经典) Posix线程是指符合 POSIX 标准的多线程技术,可以将一个进程分解成多条执行线程,每条线程都可以独立运行,并共享所在进程的资源。Posix线程技术可以提高系统的并发性和响应速度,提高系统的性能和...

    POSIX线程编程指南(合集)

    POSIX线程编程指南,通常被称为Pthreads,是操作系统接口的一部分,用于支持多线程编程。这个合集可能包含了深入的教程和实例,帮助开发者理解和掌握如何在遵循POSIX标准的系统上创建和管理线程。以下是关于POSIX...

    POSIX多线程程序设计.pdf

    《POSIX多线程程序设计》深入描述了IEEE的开放系统接口标准——POSIX线程,通常称为Pthreads标准。本书首先解释了线程的基本概念,包括异步编程、线程的生命周期和同步机制;然后讨论了一些高级话题,包括属性对象、...

    Posix线程编程指南.pdf

    #### 二、Posix线程创建详解 在Posix标准下,线程的创建主要通过`pthread_create()`函数实现,其原型如下: ```c int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)...

    POSIX多线程程序设计

    内容提要, 本书深入描述了IEEE的开放系统接口标准-POSIX线程,通常称为Pthreads标准。本, 书首先解释了线程的基本概念,包括异步编程、线程的生命周期和同步机制;然后讨论了, 一些高级话题,包括属性对象、线程私有...

    Posix线程编程指南

    POSIX线程编程是指使用POSIX线程(通常称为pthread)库在类Unix操作系统上进行多线程编程的过程。POSIX线程库是一系列用于创建和管理线程的C语言接口,它被广泛应用于Linux和其他类Unix系统中。该指南将详细介绍...

    POSIX线程编程指南.pdf

    ### POSIX线程编程指南知识点详解 #### 一、线程的创建与取消 ##### 一、线程创建 ###### 1.1 线程与进程 线程是一种比进程更细粒度的执行单元,它允许在同一个进程中并发执行多个代码路径。线程与进程之间的...

    IBM POSIX 线程编程资料

    这是将网上收集的IBM线程编程资料整理成了一个chm文件,便于使用。内容包括UNIX线程编程指南和详解部分,适合学习POSIX线程编程技术的人员使用。

    POSIX线程详细使用方法

    ### POSIX线程详解:深入理解并行编程的关键 #### 知识点一:POSIX线程的概念与背景 POSIX线程,简称Pthreads,是一种标准化的线程接口,广泛应用于Unix-like系统如Linux中,用于实现并行计算。线程作为程序执行的...

    POSIX线程相关资料打包

    POSIX线程,通常简称为pthreads,是操作系统接口(POSIX)标准的一部分,它定义了一个多线程API,允许程序创建和管理多个执行线程。这个标准在各种Unix和类Unix系统,如Linux和macOS中得到广泛支持。本文将深入探讨...

    POSIX线程详解(转)

    POSIX线程,也称为pthreads,是操作系统接口标准的一部分,用于定义线程的创建、管理及同步。线程是程序执行的独立流,可以在同一进程中并发运行,从而提高程序的响应性和性能。Daniel Robbins在文章中深入讲解了...

    (中英文)-POSIX多线程程序设计-Programming with POSIX Threads

    本书深入浅出地介绍了POSIX线程(也称为pthreads)API,是理解并掌握多线程编程的重要参考资料。在本文中,我们将探讨POSIX线程的基本概念、API用法以及在实际开发中的应用。 1. **POSIX线程基础** - POSIX线程,...

    posix线程详解 线程 进程

    POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段。在本系列中,Daniel Robbins 向您精确地展示在编程中如何使用线程。其中还涉及大量幕后细节,读完本系列文章,您完全可以运用 POSIX 线程创建多...

    POSIX线程程序设计

    POSIX线程,通常简称为pthreads,是操作系统接口的一部分,定义了多线程编程的标准。这个标准由IEEE POSIX.1c(也被称为IEEE 1003.1c)和ISO/IEC 9945-1:2003标准定义,允许开发者在支持POSIX的平台上编写可移植的多...

Global site tag (gtag.js) - Google Analytics