多线程的理论基础
线程技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者(Solaris 是Sun Microsystems研发的计算机操作系统。它被认为是UNIX操作系统的衍生版本之一。目前Solaris属于混合开源软件。2005年6月14日,Sun公司将正在开发中的Solaris 11的源代码以CDDL许可开放,这一开放版本就是OpenSolaris。)。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在多线程已经被许多操作系统所支持,包括Window/NT, Linux。
使用多线程的优势:
1.和进程相比,线程是非常节俭的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段,堆栈段和数据段,这是一种昂贵的多任务工作方式;而运行一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,一个进程的开销大概是一个线程的30倍左右。
2.对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,而这种方式不仅费时,而且很不方便。线程则不同,由于同一个进程下的线程之间共享数据空间,所以一个线程的数据可以直接被其它线程所用,这不仅快捷,而且方便。
3.使得多CPU系统更加有效,操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
4.改善程序结构,一个既长又复杂的进程可以考虑分成几个线程,成为几个独立或者半独立的运行部分,这样程序会利于理解和修改。
Linux系统下的多线程遵循POSIX线程接口,称为pthread.编写Linux下的多线程程序,需要使用pthread.h,连接时需要使用库libpthread.a。
创建线程
#include
int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(start_rtn)(void), void *arg)
tidp:线程ID
attr:线程属性(通常为空)
start_rtn:线程执行的函数
arg:start_rtn的参数
编译
因为pthread的库不是linux系统的库,所以在进行编译时需要加上 –lpthread
例如:
#gcc filename –lpthread
终止一个线程
在进程中任何一个线程中调用exit或者_exit,那么整个进程都会终止。线程的正常退出方式有:
一.从启动例程中返回
二.被另一个进程终止
三.线程自己调用pthread_exit函数
#include
void pathread_exit(void *rval_ptr)
功能:终止调用线程
rval_ptr:线程退出返回值的指针。
线程等待
#include
int pthread_join(pthread_t tid, void **rval_ptr)
功能:阻塞调用线程,直到指定的线程对出
tid: 等待退出线程的id
rval_ptr:线程退出时的返回值指针
线程标识
#include
pthread_t pthread_self(void)
功能:获取调用线程的thread identifier
线程清除
线程的终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit或者从线程函数中return都会使得线程正常退出,这是可以预见的退出方式;飞正常终止指的是线程在其它线程的干预下,或者由于自身运行处处(比如非法访问地址)而退出,这种退出方式是不可预见的。
无论是正常终止还是异常终止,都存在资源释放的问题,如何保证线程终止时可以释放掉自己占用的资源,是一个必须考虑解决的问题。
Linux的解放方案:
从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)都将执行pthread_cleanup_push()所指定的清理函数。
#include
Void pthread_cleanup_push(void (*rtn)(void *), void * arg)
功能:将清理函数压入清除栈
rtn:清除函数
arg:清除函数的参数
#include
Void pthread_cleanup_pop(int execute)
功能:将清除函数弹出清除栈
参数:
Execute:当执行到pthread_cleanup_pop()时,是否在弹出清理函数的同时,执行该函数。
非0:执行 0:不执行