对操作系统来说,进程占有系统资源,进程的切换也给操作系统带来了额外的开销。
每次创建新进程会把父进程的资源复制一份到子进程,如果创建多个进程的话,会占用大量的资源。
进程间的数据共享也需要操作系统的干预。
进程是操作系统中资源管理的最小单位。
为此,希望将进程的某些属性展开,使得:
作为独立调度的基本单位,不同时作为占有资源的基本单位
对占有资源的基本单位又不频繁切换
线程的定义:有时称轻量级进程,是进程中的一个执行线路或线索,是一个相对独立的、可独立调度和指派的执行单元。
资源的拥有者还是进程,线程将原来进程的两个属性分开处理。
线程的性质:
是进程内的一个相对独立的可执行单元;
是操作系统中的基本调度单元,在线程中包含调度所需的信息;
一个进程至少有一个线程,可有多个线程,因进程已不是被调度的单元;
线程并不拥有资源,而是共享和使用包含它的进程所拥有的所有资源;
线程在需要时也可创建其它线程。线程有自己的生命期,也有状态变化。
线程是程序执行的最小单位,是操作系统调度的最小单位,一个进程由一个或多个线程组成。
从进程演化出线程最主要的目的就是更好地支持多处理器以及减少上下文切换开销。
一个进程至少需要一个线程作为它的指令执行体,进程管理着计算机资源,而将线程分配到某个CPU上执行。
线程是一种轻量级的进程。
线程没有系统资源。
在一个进程内部,多个线程之间的资源是共享的。
实际情况中,线程执行时间会较长,超过1个时间片,系统会在多个线程间切换。
单进程、单线程
单进程、多线程
多进程、一个进程一个线程
多进程、一个进程多个线程
资源分配不同
进程拥有独立的内存和系统资源,而在一个进程内部,线程之间的资源是共享的,系统不会为线程分配系统资源。
工作效率不同
进程拥有系统资源,在系统切换的时候,操作系统要保留进程占用的资源;线程的切换不需要保留系统资源,切换效率远高于进程。
执行方式不同
线程有程序运行的入口地址,但是线程不能独立运行。由于线程不占有系统资源,所以线程必须放在进程中。进程可以被操作系统直接调度。一个进程内部的多个线程可共享资源和调度,不同进程之间的线程资源不能直接共享。
创建、撤消一个线程的系统开销小。
两个线程的调度切换方便:线程是调度的基本单位,进程是资源的拥有单位。进程可以由一个或多个线程组成。在同一进程中,线程的切换不会引起进程的切换,不同进程间的线程切换则会引起进程切换。
多线程的优点
使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间
线程间彼此切换所需的时间远远小于进程间切换所需要的时间
由于共享空间,也方便通信
函数原型
int pthread_create(pthread_t* thread, const pthread_attr_t *attr,void*(*start_rtn) (void*),void * arg);
参数说明
thread
: 待创建线程的id地址(指针)类型为pthread_t
(长整型)
attr
: 创建线程时的线程属性(暂时可忽略,NULL)
void* (*start_rtin)(void*)
: 返回值是void类型的指针函数,即线程体,其参数类型为void,即函数形式为:void * fun (void *)
arg
: 传递给线程函数的参数
返回值
成功返回0
失败返回错误编号
#include
获得线程标识符
#include
pthread_t pthread_self(void)
说明:pthread_t pthread_self()返回调用的线程的标识符。每个线程都有自己的线程标识符,以便在进程内区分,线程标识符在pthread_create创建时产生。
线程等待
#include
int pthread_join(pthread_t thread, void **retval)
说明:pthread_join()将调用它的线程阻塞,一直等到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。
第一个参数thread为被等待的线程标识符,第二个参数retval为用户定义的指针,存放被等待线程的返回值。
线程退出
#include
void pthread_exit(void *retval);
int pthread_cancel(pthread_t thread);
pthread_exit()终止调用线程,retval为线程的返回值;
pthread_cancel终止由参数thread 指定的线程。
创建一个线程,该线程显示3次字符串“This is a pthread”,父进程显示3次字符串“This is the main process”。
#include
#include
void thread(void)
{
int i;
for (i=0;i<3;i++)
printf("This is a pthread.\n");
}
int main(void)
{
pthread_t id;
int i,ret;
ret=pthread_create(&id,NULL,(void *) thread,NULL);
if (ret!=0)
{
printf ("Create pthread error!\n");
exit (1);
}
for (i=0;i<3;i++)
printf("This is the main process.\n");
pthread_join(id,NULL);
return(0);
}
#include
#include
void *create(void *arg){
printf("new thread created ...\n");
}
int main()
{
pthread_t tidp;
int error;
error=pthread_create( &tidp ,NULL, create, NULL);
pthread_join(tidp,NULL);
printf("pthread_create is created...\n");
}
#include
#include
void *create(void *arg){
//puts要求参数是char*类型,强制类型转换:
puts((char*)arg);
}
int main(int argc,char *argv[])
{
pthread_t tidp;
int error;
char* str="string from main";
pthread_create(&tidp,NULL,create,(void*)str);
}
pthread_join: 等待指定线程号的线程结束
第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值,若不需要可以为NULL
线程共享进程资源,线程间可以通过全局变量来交换数据/通信
创建线程时,可以传递参数
通过2次强制类型转换来传递
如要传多个参数,使用结构体、内存等
进程中任何一个线程中调用exit或_exit,整个进程都会终止。
线程的正常退出方式有:
线程从启动例程中return返回
线程可以被另一个进程终止pthread_cancel函数
线程自己调用pthread_exit函数