Linux线程

一、线程的概念

我们知道进程有自己独立的地址空间运行,在一个程序里的一个执行路线就叫做线程(thread)。
更准确的定义是:线程是“一个进程内部的控制序列“,一切进程至少都有一个执行线程。
进程是资源竞争的基本单位,线程是程序执行的最小单位。

1、进程的多个线程共享:

1)同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境

2)文件描述符表
3)每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
4)当前工作目录
5)用户id和组id

2、线程有些资源是每个线程各有一份的
1)线程id
2)上下文,包括各种寄存器的值,程序计数器和栈指针
3)栈空间
4)调度优先级
二、线程的优缺点

1、优点

1)创建一个新线程的代价要比创建一个新进程小得多
2)与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
3)线程占用的资源要比进程少很多
4)能充分利用多处理器的可并行数量
5)在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
6)计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
7)I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
2、缺点

1)性能损失

2)健壮性降低
3)缺乏访问控制
4)编程难度提高
三、线程的创建

1、创建线程要用pthread_creat函数


参数:

attr表示线程属性,线程调用pthread_ctreate时创建新线程,当前线程pthread_create()将继续往下执行,新线程的代码由start_routine()决定,start_routine()有一个参数,就是arg。 
返回值:
成功返回0,失败返回值错误号,以前我们知道系统函数是成功返回0,失败返回-1,而错误号保存在全局变量errno中;
而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但是这是为了兼容其他函数接口而提供的,pthread库本身并不使用它,通过返回值,返回错误码更加清晰

错误信息:

由于pthread_create的错误码不保存在errno中,因此不能直接⽤用perror(3)打印错误信息,可以先用strerror(3)把错误码转换成错误信息再打印。
start_routine()的返回值类型也是void*。

代码实现线程的创建:

  1 #include<unistd.h>
  2 #include<stdlib.h>
  3 #include<stdio.h>
  4 #include<pthread.h>
  5 #include<sys/types.h>
  6 
  7 void *thread_run(void *arg){
  8         printf("I am new thread :pid:%d,thread:%u\n",getpid(),pthread_self());
  9         sleep(5);
 10         return (void*)3;
 11 }
 12 
 13 int main(){
 14     pthread_t tid;
 15     int ret;
 16     if((ret=pthread_create(&tid,NULL,thread_run,NULL))!=0){
 17         fprintf(stderr,"pthread_create:%s\n",strerror(ret));
 18         exit(EXIT_FAILURE);
 19     }
 20     printf("i am main thread:pid:%d,thread:%u\n",getpid(),pthread_self());
 21     pthread_join(tid,NULL);
 22     return 0;
 23 }
在这里注意,pthread.h不是Linux默认的库,因此在链接时需要使用静态库libthread.a,所以在编译时要加-lpthread参数,如下:

可以看到两个线程属于同一个进程。

四、线程的终止
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
2. 线程可以调用pthread_ exit终止自己。
3. 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程。
看一下pthread_exit函数----线程终止

参数:
retval是void*类型,和线程函数返回值用法一样,其他线程调用pthread_join获得这个指针
注:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是malloc分配的,不能从线程函数的栈上分配。因为当其它线程得到这个返回值指针时,线程函数已经退出。

了解pthread_cancel函数----线程取消
参数:
thread:线程ID
返回值:成功返回0;失败返回错误码

五、线程等待

当已经退出的线程,其空间没有被释放,仍然在进程的地址空间内,或者创建新的线程不会复用刚才退出线程的地址空间时,就需要线程等待。

pthread_join函数---等待线程结束

参数:
thread:线程ID   
value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码


PS:调用该函数的线程将挂起等待,直到id为thread的线程终止。
thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
1. 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值。
2.如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_ CANCELED。
3.如果thread线程是自己调用pthread_exit终止的,valueptr所指向的单元存放的是传给pthread_exit的参数。
4. 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数。

使用函数举例:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 #include<pthread.h>
  6 
  7 void *thread1(void *arg){
  8     printf("thread 1 returning...\n");
  9     int *p=(int*)malloc(sizeof(int));
 10     *p=1;
 11     return (void*)p;
 12 }
 13 
 14 void *thread2(void *arg){
 15     printf("thread 2 exiting...\n");
 16     int *p=(int*)malloc(sizeof(int));
 17     *p=2;
 18     pthread_exit((void*)p);
 19 }
 20 
 21 void *thread3(void *arg){
 22     while(1){
 23         printf("thread3 is running..\n");
 24         sleep(1);
 25     }
 26     return NULL;
 27 }
 28 
 29 int main(){
 30     pthread_t tid;
 31     void *ret;
 32 
 33     //thread1 return
 34     pthread_create(&tid,NULL,thread1,NULL);
 35     pthread_join(tid,&ret);
 36     printf("thread return,thread id %X,return code:%\n",tid,*(int*)ret);
 37     free(ret);
 38 
 39     //thread2 exit
 40     pthread_create(&tid,NULL,thread2,NULL);
 41     pthread_join(tid,&ret);
 42     printf("thread rerurn,thread id %X,return code:%d\n",tid,*(int*)ret);
 43     free(ret);
 44 
 45     //thread 3 cancel by other
 46     pthread_create(&tid,NULL,thread3,NULL);
 47     sleep(3);
 48     pthread_cancel(tid);
 49     pthread_join(tid,&ret);
 50     if(ret==PTHREAD_CANCELED)
 51         printf("thread return,thread id %X,return code:PTHREAD_CANCELED\n",tid);
 52     else
 53         printf("thread return,thread id %X,return code:NULL\n",tid);
 54 }

结果:

六、线程的合并与分离
线程是可结合(joinable)的或者是可分离的(detached).一个线程可以被其他线程收回资源和杀死,在被其他线程回收之前,它的存储器资源是不释放,相反,一个分离的线程是不能被其他线程回收或者杀死,它的存储器资源是由系统自动释放。

1、默认情况下,线程被创建是可结合的,线程退出后,需要对其进⾏行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
2、如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
将子线程状态设置为分离(detached),该线程运行结束会自动释放所有资源。
注意:joinable和分离是冲突的,一个线程不能既是joinable又是分离的;
分离线程可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离。
函数应用如下:
函数应用举例:
1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 #include<pthread.h>
  6 
  7 void *thread_run(void *arg){
  8     pthread_detach(pthread_self());
  9     printf("%s\n",(char*)arg);
 10     return NULL;
 11 }
 12 
 13 int main(){
 14     pthread_t tid;
 15     if(pthread_create(&tid,NULL,thread_run,"thread1 run...")!=0){
 16         printf("create thread error\n");
 17         return 1;
 18     }
 19     int ret=0;
 20     sleep(1);
 21     if(pthread_join(tid,NULL)==0){
 22         printf("pthread wait success\n");
 23         ret=0;
 24     }
 25     else{
 26         printf("pthread wait failed\n");
 27         ret=1;
 28     }
 29     return ret;
 30 }

结果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值