线程概述
前面已经提到,进程是系统中程序执行和资源分配的基本单位。每个进程都拥有自己的
数据段、代码段和堆栈段,这就造成了进程在进行切换等操作时都需要有比较负责的上下文
切换等动作。为了进一步减少处理机的空转时间支持多处理器和减少上下文切换开销,进程
在演化中出现了另一个概念——线程。它是一个进程内的基本调度单位,也可以称为轻量级
进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描
述和信号处理。因此,大大减少了上下文切换的开销。
同进程一样,线程也将相关的变量值放在线程控制表内。一个进程可以有多个线程,也就
是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。要注意的是,由于线程共享
了进程的资源和地址空间,因此,任何线程对系统资源的操作都会给其他线程带来影响,因此,
多线程中的同步就是非常重要的问题了。
线程分类
线程按照其调度者可以分为用户级线程和核心级线程两种。
(1)用户级线程
用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行
选择决定,在运行时不需要特定的内核支持。在这里,操作系统往往会提供一个用户空间的
线程库,该线程库提供了线程的创建、调度、撤销等功能,而内核仍然仅对进程进行管理。
如果一个进程中的某一个线程调用了一个阻塞的系统调用,那么该进程包括该进程中的其他
所有线程也同时被阻塞。这种用户级线程的主要缺点是在一个进程中的多个线程的调度中无
法发挥多处理器的优势。
(2)核心级线程
这种线程允许不同进程中的线程按照同一相对优先调度方法进行调度,这样就可以发挥
多处理器的并发优势。
现在大多数系统都采用用户级线程与核心级线程并存的方法。一个用户级线程可以对应
一个或几个核心级线程,也就是“一对一”或“多对一”模型。这样既可满足多处理机系统
的需要,也可以最大限度地减少调度开销。
线程基本操作
这里要讲的线程相关操作都是用户空间线程的操作。在Linux 中,一般Pthread线程库是
一套通用的线程库,是由POSIX 提出的,因此具有很好的可移植性。
1.线程创建和退出
(1)函数说明创建线程实际上就是确定调用该线程函数的入口点,这里通常使用的函数是pthread_create。
在线程创建以后,就开始运行相关的线程函数,在该函数运行完之后,该线程也就退出了,这也
是线程退出一种方法。另一种退出线程的方法是使用函数pthread_exit,这是线程的主动行为。
这里要注意的是,在使用线程函数时,不能随意使用exit退出函数进行出错处理,由于exit的作
用是使调用进程终止,往往一个进程包含多个线程,因此,在使用exit之后,该进程中的所有线
程都终止了。因此,在线程中就可以使用pthread_exit 来代替进程中的exit。
由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占
用的资源并不会随着线程的终止而得到释放。正如进程之间可以用wait()系统调用来同步终
止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。pthread_join可以用
于将当前线程挂起,等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一
直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。
(2)函数格式
函数原型 int pthread_create ((pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg))
函数传入值
thread:线程标识符
attr:线程属性设
函数返回值
start_routine:线程函数的起始地址
arg:传递给start_routine的参数
成功:0
出错:-1
pthread_exit函数的语法要点
所需头文件#include
函数原型void pthread_exit(void *retval)
函数传入值Retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join 来检
索获取
pthread_join函数的语法要点
所需头文件#include
函数原型int pthread_join ((pthread_t th, void **thread_return))
函数传入值
th:等待线程的标识符
thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)
函数返回值
出错:-1
成功:0
(3)函数使用
以下实例中创建了两个线程,其中第一个线程是在程序运行到中途时调用pthread_exit
函数退出,第二个线程正常运行退出。在主线程中收集这两个线程的退出信息,并释放资源。
从这个实例中可以看出,这两个线程是并发运行的。
/*thread.c*/
#include
#include
/*线程一*/
void thread1(void)
{
int i=0;
for(i=0;i<6;i++){
printf("This is a pthread1.\n");
if(i==2)
pthread_exit(0);
sleep(1);
}
}
/*线程二*/
void thread2(void)
{
int i;
for(i=0;i<3;i++)
printf("This is a pthread2.\n");
pthread_exit(0);
}
int main(void)
{
pthread_t id1,id2;
int i,ret;
/*创建线程一*/
ret=pthread_create(&id1,NULL,(void *) thread1,NULL);
if(ret!=0){
printf ("Create pthread error!\n");
exit (1);
}
/*创建线程二*/
ret=pthread_create(&id2,NULL,(void *) thread2,NULL);
if(ret!=0){
printf ("Create pthread error!\n");
exit (1);
}
/*等待线程结束*/
pthread_join(id1,NULL);
pthread_join(id2,NULL);
exit (0);
}
阅读(696) | 评论(0) | 转发(0) |