第十章 POSIX线程

来源:互联网 发布:php中文分词算法 编辑:程序博客网 时间:2024/04/29 09:43

1.线程的定义

在一个程序中的多个执行路线就叫做线程(thread)。更准确的定义是:线程是一个进程内部的一个控制序列。

当进程执行fork调用时,将创建出该进程的一份新副本。这个进程拥有自己的变量和自己的PID,它的时间调度也是独立的,它的执行(通常)几乎完全独立与父进程。当在进程中创建一个新线程时,新的执行线程将拥有自己的栈(因此也有自己的局部变量),但与它的创建者共享全局变量、文件描述符、信号处理函数和当前目录状态。

2.线程的有点和缺点

优点:线程之间的切换需要操作系统做的工作要比进程之间的切换少得多,因此多个线程对资源的需求要远小于多个进程。

缺点:编写多线程程序需要非常仔细的设计,在多线程程序中,因时序上的细微偏差或无意造成的变量共享而引发错误的可能性很大。

对多线程程序的调试要比对单线程程序的调试困难得多,因为线程之间的交互非常难于控制。

3.在设计最初的UNIX和POSIX库例程中,人们假设每个进程中只有一个执行线程。一个明显的例子就是errno,在一个多线程程序中,默认情况下,只有一个errno变量供所有的线程共享。在一个线程准备获取刚才的错误代码时,该变量很容易被另一个线程中的函数调用所改变。类似的问题还存在于fputs之类的函数中,这些函数通常用一个全局性区域来缓存输出数据。

为了解决这个问题,我们需要使用被称为可重入的例程。可重入代码可以被多次调用而仍然正常工作,这些调用可以来自不同的线程,也可以是某种形式的嵌套调用。因此,代码中的可重入部分通常只使用局部变量,这使得每次对该代码的调用都将获得它自己的唯一的一份数据副本。

编写多线程程序时,我们需要通过定义宏_REENTRANT来告诉编译器我们需要可重入功能。

这个宏的定义必须位于程序中任何#include语句之前。这将为我们完成3件事:

(1)它会对部分函数重新定义它们的可安全重入的版本,这些函数的名字一般不会发生改变,只是会在函数名后面加上_r字符串。

(2)stdio.h中原来以宏的形式实现的一些函数将变成可安全重入的函数。

(3)在errno.h中定义的变量errno现在将成为一个函数调用,它能够以一种多线程安全的方式来获取真正的errno值。

一个可重入的函数。简单理解为可以被中断的函数。就是说,你可以在这个函数执行的任何时候中断他的运行,在任务调度下去执行另外一段代码而不会出现什么错误。而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,这类函数是不能运行在多任务环境下的。

4.线程的属性

假设我们在主线程继续为用户服务的同时创建了第二个线程,新线程的作用是将用户正在编辑的数据文件进行备份存储。备份工作结束后,第二个线程就可以直接终止了,它没有必要再回到主线程中。我们可以直接创建这一类线程,它们被称为脱离线程。也可以通过修改线程属性或者调用pthread_detach的方法来创建它们。

#include

int pthread_attr_init(pthread_attr_t *attr);

功能:初始化一个线程属性对象。成功时返回0,失败时返回错误代码。

还有一个回收函数pthread_attr_destroy,它的目的是对属性对象进行清理和回收。一旦对象被回收了,除非它重新被初始化,否则就不能再次使用。初始化一个线程属性对象后,我们可以调用许多其他的函数来设置不同的属性行为。主要的一些函数一般在pthread.h条目下,这里主要介绍detachedstate和schedpolicy两个:

#include

int pthread_attr_setdetachstate(pthread_attr_t *attr, intdetachstate);

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int*detachstate);

int pthread_attr_setschedpolicy(pthread_attr_t *attr, intpolicy);

int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int*policy);

detachedstate:这个属性允许我们无需对线程进行重新合并。与大多数_set类函数一样,它以一个属性指针和一个标志为参数来确定需要的状态。pthread_attr_setdetachstate函数可能用到的两个标志分别是PTHREAD_CREATE_JOINABLE和PTHREAD_CREATE_DETACHED。这个属性的默认标志值是PTHREAD_CREATE_JOINABLE,所以可以允许两个线程重新合并。如果标志设置为PTHREAD_CREATE_DETACHED,就不能调用pthread_join来获得另一个线程的退出状态。

schedpolicy:这个属性控制线程的调度方式。它的取值可以是SCHED_OTHER、SCHED_RP和SCHED_FIFO。这个属性的默认值为SCHED_OTHER。另外两种调度方式只能用于以超级用户权限运行的进程,因为它们都具备实时调度的功能,但在行为上略有区别。SCHED_RP使用循环调度机制,而SCHED_FIFO使用“先进先出”机制。

schedparam:这个属性是和schedpolicy属性结合使用的,它可以对以SCHED_OTHER策略运行的线程的调度进行控制。

inheritsched:这个属性可取两个值:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED。它的默认取值是PTHREAD_EXPLICIT_SCHED,表示调度由属性明确地设置。如果把它设置为PTHREAD_INHERIT_SCHED,新线程将沿用其创建者所使用的参数。

scope:这个属性控制一个线程调度的计算方式,目前Linux只支持它的一种取值PTHREAD_SCOPE_SYSTEM。

stacksize:这个属性控制线程创建的栈的大小,单位为字节。它属于POSIX规范中的“可选”部分,只有在定义了宏_POSIX_THREAD_ATTR_STACKSIZE的实现版本中才支持。Linux在实现线程时,默认使用的栈很大,所以这个功能对于Linux来说显得有些多余。

线程属性——调度

(1)首先,定义一些额外的变量:

int max_priority;

int min_priority;

sturct sched_param scheduling_value;

(2)设置好脱离属性后,设置调度策略:

res = pthread_attr_setschedpolicy(&thread_attr,SCHED_OTHER);

if(res != 0)

{

perror(“Setting scheduling policy failed”);

exit(EXIT_FAILURE);

}

(3)接下来查找允许的优先级范围

max_priority = sched_get_priority_max(SCHED_OTHER);

min_priority = sched_get_priority_min(SCHED_OTHer);

(4)设置优先级

scheduling_value.sched_priority = min_priority;

res = pthread_attr_setschedparam(&thread_attr,&scheduling_value);

if(res != 0)

{

   perror(“Setting scheduling priority failed”);

   exit(EXIT_FAILURE);

}

5.取消一个线程

一个线程可以要求另一个线程终止。

#include

int pthread_cancel(pthread_t thread);

这个函数的定义简单易懂,就是提供一个线程标识符,就可以通过发送请求来取消它。接收方的线程可以使用下面的函数来设置自己的取消状态:

#include

int pthread_setcancelstate(int state, int *oldstate);

第一个参数的取值可以是PTHERAD_CANCEL_ENABLE,这个值允许线程接收取消消息;或者是PTHERAD_CANCEL_DISABLE,它的作用是忽略取消请求。oldstate指针用于获取先前的取消状态,如果你对这个参数没有兴趣,只需传递NULL给它。如果取消请求被接受了,线程就可以进入第二个控制层次,用pthread_setcanceltype设置取消类型。

#include

int pthread_setcanceltype(int type, int *oldtype);

type参数可以有两种取值:一个是PTHREAD_CANCEL_ASYNCHRONOUS,它将使得在接收到取消请求后立即采取行动;另一个是PTHREAD_CANCEL_DEFERRED,它将使得在接收到取消请求后,一直等待直到线程执行了下述函数之一后才采取行动。pthread_join,pthread_cond_wait,pthread_cond_timedwait,pthread_testcancel,sem_wait或sigwait。oldtype参数可以保存先前的状态,如果不想知道先前的状态,可以传递NULL给它。

0 0
原创粉丝点击