Linux之线程小议

1.线程与进程的关系

说到线程概念,必须先说明进程。进程是一个运行中的程序,在操作系统中,一个程序运行起来后就会被加载到内存中。操作系统创建了一个进程描述符(PCB)对程序的运行进行描述控制。因此进程就是PCB,在Linux下用task_struct结构体来描述。Linux系统下,用进程PCB来模拟线程,因此Linux下一个线程就是一个轻量级进程。如果说PCB称为了线程,那么进程就是线程组。一个进程中至少有一个或多个线程。

因为Linux下PCB是一个线程,因此线程是CPU调度的基本单位。因为程序运行时候分配资源,进程(线程组)是资源分配的基本单位。进程中的所有线程共用一个虚拟地址空间,因此可以共享进程的代码段和数据段又因为线程之间数据的共享,所以线程之间进行通信就变得极为简单

因为每个线程都是PCB,是CPU调度的基本单位,因此线程可以同时运行,但不会造成调用栈混乱,主要是因为每个线程都有自己的独有数据

  1. 上下文数据
  2. 信号屏蔽字
  3. errno
  4. 线程标识符

既然多进程可以并行处理任务,多线程也可以。其优缺点分析如下(根据具体使用情况):
多线程的优点: 因为线程共享虚拟地址空间,线程间通信简单,线程的创建/销毁成本更低,线程的执行粒度更细。
多线程缺点: 线程缺乏访问控制(可以访问虚拟地址空间中的任何一块数据);但线程的某些错误会导致整个进程退出,即健壮性较低。
注意:线程的数量也并非越多越好,因为过多的话会导致切换频繁,在一定程度上反而会降低性能。

2.线程控制

操作系统并没有提供直接的创建线程的接口(用户创建线程很麻烦),因此前辈们实现了一套线程控制接口供用户使用。因此我们说创建的线程是一个用户态的线程,但是在内核对应有一个轻量级进程实现程序的调度运行。

2.1 线程创建

int pthread_create(pthread_t *thread, pthread_addr_t *arr,void* (*start_routine)(void *), void *arg);

//thread    :用于返回创建的线程的ID
//arr         : 用于指定的被创建的线程的属性,上面的函数中使用NULL,表示使用默认的属性
//start_routine      : 这是一个函数指针,指向线程被创建后要调用的函数
//arg        : 用于给线程传递参数,在本例中没有传递参数,所以使用了NULL

2.2 线程终止
如果需要只终止某个线程而不终止整个进程,可以有以下三种方法:

  1. 从线程函数return。这种方法对主线程不适用,从main函数return相当调用exit.
    (在main中return,退出整个进程;在普通入口函数中return,只是退出调用线程)
  2. 线程可以调用pthread_exit来终止自己(退出调用线程)
  3. pthread_cancel用来取消指定线程,也可以取消自己。

pthread_exit()函数

//功能:线程终止
//原型:
void pthread_exit(void* value_ptr);
//参数:
 value_ptr:不能指向一个局部变量
//返回值:无。跟进程一样,线程结束的时候无法返回到它的调用者。

pthread_cancel()函数

//功能:取消一个执行中的线程
//原型:
int pthread_cancel(pthread_t thread);
//参数:
 thread: 线程ID
//返回值:成功返回0,失败返回错误码

2.3 线程等待
为什么要进行线程等待呢?简言之,线程退出后可能会产生“僵尸线程”,所以要等待,以免造成资源泄露。换句话说,即:
等待指定线程退出,就是要获取指定线程的返回值,回收线程资源。因为一个线程被创建后,默认有一个属性为joinable,处于这个属性的线程必须被等待,因为线程退出后,不会自动地回收资源,会造成资源泄露

pthread_join()

//功能:等待线程结束
//原型:
int pthread_join(pthread_t thread, void** value_ptr);
//参数:
thread:线程ID
value_ptr:指向一个指向被连接线程的返回码的指针的指针
//返回值:成功返回0, 失败返回错误码。

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,value_ptr所指向的单元里存放的是常熟PTHREAD_CANCELED。
  3. 如果thread线程是自己调用pthread_exit()终止的,value_ptr所指向的单元存放的是传给pthread_exit()的参数。
  4. 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数。

2.4 线程分离
为什么要进行线程分离呢?(通俗点来说,“对谁不关心,就去分离谁,不去等待谁”)。 即:
分离一个线程,将线程的joinable属性修改为detach属性,处于此属性的线程,退出后将自动回收资源。此属性的线程,不能被等待,否则就会报错。

  1. 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成资源泄露;
  2. 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
//线程组内其他线程对目标线程进行分离
int pthread_detach(pthread_t thread);


//也可以是线程自己分离自己
int pthread_detach(pthread_self());
//pthread_self()函数获得线程自身的ID
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值