线程的概念:线程是运行在进程内的一个基本执行流,和进程共享地址空间及资源(类似于父子进程共享地址空间),但每个也有自己的私有资源。
进程强调独占性
每个进程都有它独立的地址空间,包括Text Segment、Data Segment等
线程强调共享性
线程的共享资源:
1.进程代码段
2.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)
3.进程打开的文件描述符
4.信号的处理器
5.进程的当前目录和进程用户ID与进程组ID
线程的私有资源:(线程实现并发性)
1.线程ID
每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标识线程。
2.寄存器组的值
由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线程切换到另一个线程上时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程在被重新切换到时能得以恢复。
3.线程的堆栈
堆栈是保证线程独立运行所必须的。
线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程必须拥有自己的函数堆栈,使得函 数调用可以正常执行,不受其他线程的影响。
4.错误返回码
由于同一个进程中有很多个线程在同时运行,可能某个线程进行系统调用后设置了errno值,而在该线程还 没有处理这个错误,另外一个线程就在此时被调度器投入运行,这样错误值就有可能被修改。
所以,不同的线程应该拥有自己的错误返回码变量。
5.线程的信号屏蔽码
由于每个线程所感兴趣的信号不同,所以线程的信号屏蔽码应该由线程自己管理。但所有的线程都共享同样 的信号处理器。
6.线程的优先级
由于线程需要像进程那样能够被调度,那么就必须要有可供调度使用的参数,这个参数就是线程的优先级。
线程控制
一、函数的原型
线程的创建
原 型:pthread_t pthread_create(pthread_t *thread,const pthread_attr_t *attr,
void *(start routine)(void *),void *arg);
返回值:成功返回0,失败返回错误码
参 数:thread:创建成功后其指向的内存存放线程id
attr:线程属性,可设为NULL
start routine:是一个函数指针,指向该线程所要函数的地址
arg:第三个参数中所要传递的参数,如果参数不止一个可以传一个结构体
线程的等待
原 型:int pthread_join(thread_t thread,void **retval);
返回值:成功返回0,失败返回错误码,对分离状态的线程进行pthread_join的调用会产生失败。 返回EINVAL。
参 数:
thread:线程id
retval:用来存储被等待线程的返回值
功 能: 以阻塞的方式等待thread指定的线程结束,当函数返回时,被等待线程的资源被收回。
如果线程已经结束,该函数会立即返回
并且thread指定的线程必须是joinable(可结合)的。
线程的终止和取消
由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的 资源并不会随着线程的终止而得到释放,但是可以用pthread_join()函数来同步并释放资源。
void pthread_exit(void* revtal);
int pthread_cancel(pthread_t thread); 成功返回0,失败返回错误编号
三种方法
1.一个线程完成它的任务后直接从线程函数return(下面thread_run1())
2.执行完自己的代码后调用pthread_exit()自己终止(下面thread_run2())
3.让同一进程中别的线程来取消自己,调用pthread_cancle(void *);(下面thread_run3())
注:exit和_exit是退出当前进程,而pthread_exit是退出当前线程。
线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略、或 者立即终止、或者继续运行至Cancelation-point(取消点),由不同的Cancelation状态决定。pthread_cancle只是向目标线程发送一个取消请求,之后函数立即返回。而目标线程在取消请求发出以后还是继续运行,直到线程到达某个取消点。取消点是线程检查自身是否被取消,并按照可取消状态进行动作的一个位置。
可取消状态:线程启动时的默认可取消状态是PTHREAD_CANCEL_ENABLE。 PTHREAD_CANCEL_ENABLE: 表示允许取消。PTHREAD_CANCEL_DISABLE:即不允许取消(收到的取消请求将被忽略)
原 型:pthread_t pthread_self();
返回值:总是成功的,返回调用它的线程id
在编译时注意加上-lpthread参数,以调用链接库。因为pthread并非Linux系统的默认库,而是posix线程库,在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显示的链接该库。函数在执行错误时的错误信息将作为返回值返回,并不修改系统全局变量errno,当然也无法使用perror()打印错误信息。
二、代码实现
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> void* thread_run1(void *arg) { printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),pthread_self()); return (void*)0; } void* thread_run2(void *arg) { printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),pthread_self()); pthread_exit((void*)1); } void* thread_run3(void *arg) { // sleep(2); printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),pthread_self()); // return NULL; } int main() { pthread_t tid1,tid2,tid3; int err1,err2,err3; err1=pthread_create(&tid1,NULL,thread_run1,(void*)1); err2=pthread_create(&tid2,NULL,thread_run2,(void*)2); err3=pthread_create(&tid3,NULL,thread_run3,(void*)3); if(err1!=0||err2!=0||err3!=0){ if(err1==0) printf("%s\n",strerror(err1)); if(err2==0) printf("%s\n",strerror(err2)); if(err3==0) printf("%s\n",strerror(err3)); } void *status; err1=pthread_join(tid1,&status); printf("thread1 return,code:%d\n",(int)status); err2=pthread_join(tid2,&status); printf("thread2 exit,code:%d\n",(int)status); err3=pthread_cancel(tid3); if(err3!=0){ printf("%s\n",strerror(err3)); } err3=pthread_join(tid3,&status); printf("thread3 cancel,code:%d\n",(int)status); int count=5; while(count-- >0){ printf("this is main thread:pid:%d,tid:%u\n",getpid(),pthread_self()); sleep(1); } return 0; }
运行结果:
函数thread_run3()中加上sleep(2)这条语句时,线程tid3还没有执行完就被别的线程取消,所以退出码是-1
运行结果:
函数thread_run3()中没有sleep(2)时,线程tid3执行完才被别的线程取消,所以退出码是40,输出的错误消息是No such process
如果thread_run1()中获得当前线程的id不调用pthread_self(),而是定义一个全局变量来表示可以吗?
test.c
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> pthread_t tid1;//全局变量 void* thread_run1(void *arg) { printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),tid1); return (void*)0; } void* thread_run2(void *arg) { printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),pthread_self()); pthread_exit((void*)1); } int main() { pthread_t tid2; int err1,err2; err1=pthread_create(&tid1,NULL,thread_run1,(void*)1); err2=pthread_create(&tid2,NULL,thread_run2,(void*)2); if(err1!=0||err2!=0){ if(err1==0) printf("%s\n",strerror(err1)); if(err2==0) printf("%s\n",strerror(err2)); } void *status; err1=pthread_join(tid1,&status); printf("thread1 return,code:%d\n",(int)status); err2=pthread_join(tid2,&status); printf("thread2 code:%d\n",(int)status); printf("this is main thread:pid:%d,tid:%u\n",getpid(),pthread_self()); return 0; }
运行结果:
线程的分离
在任何时刻线程是可结合的(joinable)或者是分离的(detached)
一个可结合的线程可以被其它线程所回收其资源或杀死(等待回收,取消杀死),在被回收之前其资源是不被释放的,而一个可分离的线程在其终止后其资源被系统自动回收,它不可以被其他线程回收或杀死。
一般情况下,线程终止后其资源还未被系统回收,其终止状态一直保留到其它线程调用pthread_join来获取它的退出状态,但其它线程调用pthread_join来等待该线程退出时,会出于阻塞状态,我们有时候不希望阻塞等待,因此可以把线程设置为detach状态,即把设置该线程为分离状态,这样,当线程结束时会立即回收它所占用的资源
一个被设置为分离状态的进程不能被其它线程调用pthread_join来等待
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> pthread_t tid1; void* thread_run1(void *arg) { int err=pthread_detach(tid1); if(err!=0){ printf("%s\n",strerror(err)); } else printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),tid1); return (void*)5; } int main() { int err1; err1=pthread_create(&tid1,NULL,thread_run1,(void*)1); if(err1!=0) printf("%s\n",strerror(err1)); void *status; // sleep(1); err1=pthread_join(tid1,&status); if(err1!=0) printf("%s\n",strerror(err1)); else printf("thread1 return,code:%d\n",(int)status); printf("this is main thread:pid:%d,tid:%u\n",getpid(),pthread_self()); return 0; }
运行结果:
有sleep(1)这条语句
线程1被设置为分离状态,运行终止后系统自动回收资源,所以主线程等待失败
运行结果:
屏蔽sleep(1)
一个被等待后的线程已经被回收,不能再调用pthread_detach设置分离状态
代码:
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> pthread_t tid1; void* thread_run1(void *arg) { printf("this is thread%d:pid:%d,tid:%u\n",(int)arg,getpid(),tid1); } int main() { int err1; err1=pthread_create(&tid1,NULL,thread_run1,(void*)1); if(err1!=0) printf("%s\n",strerror(err1)); void *status; err1=pthread_join(tid1,&status); if(err1!=0) printf("%s\n",strerror(err1)); else printf("thread1 return,code:%d\n",(int)status); err1=pthread_detach(tid1); if(err1!=0) printf("detach is failed:%s\n",strerror(err1)); printf("this is main thread:pid:%d,tid:%u\n",getpid(),pthread_self()); return 0; }
运行结果:
本文出自 “零蛋蛋” 博客,请务必保留此出处http://lingdandan.blog.51cto.com/10697032/1764813
原文地址:http://lingdandan.blog.51cto.com/10697032/1764813