Linux多线程编程

      线程是处理机调度的基本单位。使用多线程的理由之一是和进程相比,它是一种非常“节俭”的多任务操作方式。启动一个线程所花费的空间远远小于启动一个进程花费的空间,而且,线程间彼此切换所需的时间也远远少于进程间切换所需的时间。

     与进程相比,线程间的关系紧密得多。虽然各线程为保持自己的控制流而独有寄存器和堆栈,但由于两个线程从属于同一个进程,它们共享同一个地址空间,所以动态堆、静态数据区及程序代码为各线程共享。

    使用多线程的理由之二是线程间方便的通信机制。对于不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式既费时又不方便。而线程不然。

     与进程相比,多线程程序作为一种多任务、并发的工作方式,还有以下优点:

(1)提高应用程序响应,特别是对于图形界面程序尤其有意义;

(2)改善程序结构,一个既长又复杂的进程可以考虑分为多个线程,这样可以使程序利于理解和修改。

    Linux系统下的多线程实现

    Linux系统下的多线程遵循POSIX线程接口,称为PTHREAD。编写Linux下的多线程程序,需要头文件pthread.h,连接是需要库文件libpthread.a。PTHREAD库中有大量的API函数。下面介绍的主要是线程创建、挂起和退出的几个主要函数。

 (1)线程创建函数:pthread_create()

 #include<pthread.h>

 int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void arg);

函数pthread_create用来创建一个线程,第一个参数为指向线程标志符的指针;第二个参数用来设置线程属性,NULL表示使用默认属性的线程;第三个参数是线程运行函数的起始地址;最后一个参数是运行函数的参数,NULL表示不需要参数。当创建线程成功时,函数返回0;若不为0,则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL,前者表示系统限制创建线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。

(2)线程等待函数:pthread_join()

#include<pthread.h>

int pthread_join(pthread_t th, void **thread_return);

pthread_join函数用来等待另一个线程的结束。该函数可以阻塞调用它的线程,直到被等待的线程结束,函数才返回,被等待的线程的资源就被回收。该函数类似于进程间的wait函数,用来同步终止并释放资源,而在一般情况下,线程退出之后,该线程所占用的资源并不会随着线程终止而得到释放。第一个参数是被等待的线程标志符,第二个参数是用户定义的一个用来存储被等待线程的返回值,该函数是一个线程阻塞函数。

(3)线程结束函数:pthread_exit()

#include<pthread.h>

void pthread_exit(void *retval);

线程结束有两种方式,一种是线程创建后,就开始运行相关的线程函数,函数结束了,调用它的线程就结束了;另一种是线程的主动行为,通过调用pthread_exit函数。需要注意的是,在使用线程函数时,不能随便调用exit退出函数进行错误处理,因为exit的作用是使调用进程终止。pthread_exit函数唯一的参数是函数的返回代码,只要pthread_join的第二个参数pthread_return不是NULL,这个值将被传递给thread_return,最后,要注意的是一个线程不能被多个线程等待否则第一个接收到信号的线程成功返回,其余的调用pthread_join的线程则返回错误代码ESRCH。

    修改线程属性

    线程的属性结构为pthread_attr_t,定义在头文件pthreadh.h中。属性值不能直接设置,需要使用相关函数进行操作,初始化函数是pthread_attr_init,这个函数必须在pthread_create函数之前调用。属性值包括是否绑定、是否分离、堆栈地址、堆栈大小和优先级。默认的属性是非绑定、非分离、缺省1MB的堆栈和与父进程同样级别的优先级。

(1)绑定属性

   系统对线程资源的分配和对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或者多个线程。默认情况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统控制的,这种状况即为非绑定的。绑定状况下,线程将被绑定在一个轻进程上。被绑定的线程具有较高的需要速度,因为CPU时间片的调度是面向轻进程的,被被绑定的线程可以保证在需要的时候它总有一个轻进程可以用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。下面的代码即创建一个绑定的线程。

#include<pthread.h>

pthread_attr_t attr;

pthread_t tid;

pthread_attr_init(&attr);     /*初始化为属性值,均为默认属性值*/

pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 

pthread_create(&tid, &attr, (void *)my_function, NULL);

注:设置线程绑定状态的函数为pthread_attr_setscope,第一个参数是向属性结构体的指针,第二个参数是绑定类型,它有两个取值:PTHREAD_SCOPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)。

(2)分离属性

线程的分离状态决定一个线程以什么样的方式来终止自己。非分离状态的线程只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占有的资源。而分离线程不是这样的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。设置分离状态的线程的函数为:

pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和PTHREAD_CREATE_JOIUABLE(非分离线程)。但要注意的是,如果设置一个线程为分离线程,而这个线程又运行得非常快,它可能在pthread_create函数返回之前就终止了,导致调用pthread_create的线程得到错误的线程号。要避免这样的情况,可以采取一定的同步措施,最简单地方法之一是在被创建的线程里调用pthread_cond_timewait函数,让线程等一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间是多线程编程常用的方法。但是要注意不要使用诸如waite()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。

(3)优先级

线程优先级存放在结构sched_param中。用函数pthread_attr_getschedparam和pthread_attr——setschedparam进行存放。一般说来,总是先取优先级,对取得的值修改后再存放回去。下面是简单地例子:

#include<pthread.h>

#include<sched.h>

pthread_attr_t attr;

pthread_t tid;

sched_param param;

int newprio = 20;

pthread_attr_init(&attr);

pthread_attr_getschedparam(&attr, &param);

param.sched_priority = newprio;

pthread_attr_setschedparam(&attr, &)











































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值