posix多线程程序设计pdf,posix多线程编程
让我们看看我们可能想要改变的第二个线程属性:调度。更改scheduling属性类似于设置separation属性,但是我们可以使用另外两个函数来查找可用的层次级别,sched_get_priority_max和sched_get_priority_min。
测试计划
因为thread6.c和前面的例子很像,这里我们只看区别。
1.首先,我们需要一些额外的变量:
int max _ priority
int min _ priority
struct sched_param调度值;
2在我们设置了分离属性之后,我们设置了调度策略。
RES=pthread _ attr _ setschedpolicy(thread _ attr,SCHED _ OTHER);
if (res!=0) {
perror(“设置计划策略失败”);
退出(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(“设置调度优先级失败”);
退出(EXIT _ FAILURE);
}
这个例子类似于设置分离状态属性,除了我们设置调度策略。
有时我们希望一个线程可以请求另一个线程结束,而不是向它发送信号。线程有办法完成这项任务,并使用并行信号处理。当线程被要求结束时,它们有办法修改自己的行为。
让我们首先看看请求线程结束的函数:
#include pthread.h
int pthread _ cancel(pthread _ t thread);
这个函数声明表明,给定一个线程标识符,我们可以请求它关闭。收到关闭请求后,事情有点复杂,但不是很多。线程可以使用pthread_setcancelstate来设置其关闭状态。
#include pthread.h
int pthread _ setcancelstate(int state,int * old state);
第一个参数是PTHREAD_CANCEL_ENABLE,它允许线程接收关闭请求,或者是PTHREAD_CANCEL_DISABLE,它使函数忽略关闭请求。oldstate指针允许您获取以前的状态。如果我们对这个状态不感兴趣,我们可以简单地传递一个NULL。如果关闭请求被接受,线程可以采用第二级控件,即关闭类型,它由pthread_setcanceltype设置。
#include pthread.h
int pthread _ setcanceltype(int type,int * old type);
这种类型的值可以是PTHREAD_CANCEL_ASYNCHRONOUS,它可以在收到关闭请求后立即执行,也可以是PTHREAD_CANCEL_DEFERRED,它使关闭请求一直等待,直到执行以下函数之一:pthread_join、pthread_cond_wait、Pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
我们在本章中看不到这些函数,因为并不是所有的函数都是必需的。和以前一样,更详细的信息可以在手册中找到。
同样,oldtype允许获取以前的状态。如果我们对先前的状态不感兴趣,我们可以传递一个NULL。默认情况下,线程从关闭状态PTHREAD_CANCEL_ENABLE和关闭状态PTHREAD_CANCEL_DEFERRED开始。
测试关闭螺纹。
我们这里的程序thread7.c是从thread1.c发展而来的,这一次,主线程向它创建的线程发送一个关闭请求。
#包含stdio.h
#包含stdlib.h
#包含字符串. h
#包括unistd.h
#include pthread.h
void * thread _ function(void * arg);
int main()
{
int res
pthread _ t a _ thread
void * thread _ result
res=pthread_create( a_thread,NULL,thread_function,NULL);
if(res!=0)
{
perror(“线程创建失败”);
退出(EXIT _ FAILURE);
}
睡眠(3);
printf(取消线程./n’);
RES=pthread _ cancel(a _ thread);
if(res!=0)
{
perror(“线程取消失败”);
退出(EXIT _ FAILURE);
}
printf(等待线程完成./n’);
res=pthread_join(a_thread,thread _ result);
if(res!=0)
{
perror(“线程加入失败”);
退出(EXIT _ FAILURE);
}
退出(EXIT _ SUCCESS);
}
void *thread_function
{
int i,res
RES=PTHREAD _ setcancelstate(PTHREAD _ CANCEL _ ENABLE,NULL);
if(res!=0)
{
perror( Thread pthread _ setcancelstate失败);
退出(退出_失败);
}
RES=PTHREAD _ setcanceltype(PTHREAD _ CANCEL _ DEFERRED,NULL);
if(res!=0)
{
perror( Thread pthread _ setcanceltype失败);
退出(退出_失败);
}
printf(线程_函数正在运行/n’);
for(I=0;我我)
{
printf(线程仍在运行(%d)./n ,I);
睡眠(1);
}
pthread _ exit(0);
}
在用通常的方法创建一个新线程之后,主线程休眠(允许新线程启动)并且发送一个关闭请求。
睡眠(3);
printf(取消线程./n’);
RES=pthread _ cancel(a _ thread);
if(res!=0)
{
perror(“线程取消失败");
退出(退出_失败);
}
在所创建的线程中,我们首先设置关闭状态允许关闭。
RES=PTHREAD _ setcancelstate(PTHREAD _ CANCEL _ ENABLE,NULL);
if(res!=0)
{
perror( Thread pthread _ setcancelstate失败);
退出(退出_失败);
}
然后我们设置关闭类型。
RES=PTHREAD _ setcanceltype(PTHREAD _ CANCEL _ DEFERRED,NULL);
if(res!=0)
{
perror( Thread pthread _ setcanceltype失败);
退出(退出_失败);
}
最后线程等待关闭。
for(I=0;我我)
{
printf(线程仍在运行(%d)./n ,I);
睡眠(1);
}
直到现在,我们总是使得程序的一个执行线程只创建一个线程。然而,我们不希望使得大家认为我们只能创建一个线程。
试验-多线程
作为我们本章的最后一个例子,thread8.c,我们演示如何在同一个程序中创建多个线程,并且以他们启动的不同顺序来收集这些线程。
#包含标准视频
#包含标准库
#包含字符串。h
#包括unistd.h
#include pthread.h
#定义线程数6
void * thread _ function(void * arg);
int main()
{
内部资源
pthread _ t a _ thread[NUM _ THREADS];
void *线程_结果
int lots _ of _ threads
for(lots _ of _ threads=0;线程数量;大量线程)
{
RES=pthread _ create((a _ thread[lots _ of _ threads]),NULL,thread_function,(void *)lots _ of _ threads);
if(res!=0)
{
perror(“线程创建失败");
退出(退出_失败);
}
睡眠(1);
}
printf(正在等待线程完成./n’);
for(lots _ of _ THREADS=NUM _ THREADS-1;线程的批次线程的批次-)
{
RES=pthread _ join(a _ thread[lots _ of _ threads],thread _ result);
if(res==0)
{
printf(拿起一个线程/n’);
}
其他
{
perror(pthread_join失败);
}
}
printf( All done/n );
退出(退出_成功);
}
void *线程_函数
{
int my _ number=*(int *)arg;
整数数量
printf(线程_函数正在运行。参数为%d/n ,我的号码);
RAND _ num=1(int)(9.0 * RAND()/(RAND _ MAX 1.0));
sleep(rand _ num);
printf(Bye from %d/n ,my _ number);
pthread_exit(空);
}
当我们运行这个程序时,我们会得到下面的输出:
$ ./线程8
线程_函数正在运行。争吵
线程_函数正在运行。争吵
线程_函数正在运行。争吵
线程_函数正在运行。争吵
线程_函数正在运行。争吵
从一开始再见
线程_函数正在运行。争吵
等待线程完成.
5点再见
捡起一根线
从0再见
两点再见
3点再见
四点再见
捡起一根线
捡起一根线
捡起一根线
捡起一根线
捡起一根线
全部完成
正如我们所看到的,我们创建了多个线程,并且允许他们以乱序结束。在这个程序中存在一个bug,如果我们由启动线程的循环中移除睡眠调用就会得到验证。我们包含就要演示当我们使用线程编写程序时需要小心。可以定位吗?我们会在下面的工作原理部分进行解释。
这一次我们创建一个线程身份数组:
pthread _ t a _ thread[NUM _ THREADS];
并且循环来创建多个线程:
for(lots _ of _ threads=0;线程的数量线程的数量;lots_of_threads ) {
RES=pthread _ create((a _ thread[lots _ of _ threads]),NULL,
thread_function,(void *)lot _ of _ threads);
if (res!=0) {
perror(“线程创建失败");
退出(退出_失败);
}
睡眠(1);
}
这些线程在退出前会随机等待一段时间:
void * thread _ function(void * arg){
int my _ number=*(int *)arg;
int rand_num
printf(thread_function正在运行。参数为%d/n ,my _ number);
RAND _ num=1(int)(9.0 * RAND()/(RAND _ MAX 1.0));
sleep(rand _ num);
printf(Bye from %d/n ,my _ number);
pthread_exit(空);
}
在主线程中,我们等待收集这些线程,但不是按照它们被创建的顺序。
for(lots _ of _ THREADS=NUM _ THREADS-1;线程批次线程批次—)
{
RES=pthread _ join(a _ thread[lots _ of _ threads],thread _ result);
if (res==0) {
printf(拿起一个线程/n );
}
否则{
perror(pthread_join失败);
}
}
如果我们运行一个没有睡眠调用的程序,我们会看到一些奇怪的效果,包括一些线程以相同的参数开始。我们对这些情况进行定位了吗?线程以一个局部变量作为线程函数的参数开始。这个变量在一个循环中更新。此更新发生在以下代码行中:
for(lots _ of _ threads=0;线程的数量线程的数量;lots_of_threads ) {
RES=pthread _ create((a _ thread[lots _ of _ threads]),NULL,
thread_function,(void *)lot _ of _ threads);
如果主线程运行的足够快,他会为一些线程修改这个参数。类似的行为是由于在使用共享变量和多执行路径时注意不够造成的。我们已经警告过你,螺纹需要仔细设计。为了解决这个问题,我们需要像下面这样直接传递这个值:
RES=pthread _ create((a _ thread[lots _ of _ threads]),NULL,thread_function,(void
*)lot _ of _ threads);
并修改thread_function:
void * thread _ function(void * arg){
int my _ number=(int)arg;
在本章中,我们学习了如何在一个进程中创建多个执行线程,并且每个线程共享文件域变量。然后,讨论了线程控制使用信号量和互斥对关键代码和数据的访问方法。之后我们讨论了线程属性的控制,以及我们如何把它们从主线程中分离出来,让他不用等他创建的线程结束。在快速理解了一个线程如何请求另一个线程完成以及接收线程如何管理这些请求之后,我们提供了一个执行多个并行线程的例子。
我们没有足够的篇幅来讨论每一个函数调用和相关线程,但现在我们应该有足够的知识来使用线程编写我们的程序,并且我们可以通过阅读手册页来探索更多的线程知识。