linux多线程(1)-----线程概念&线程控制

1.线程概念

1.1线程的概念

要理解线程得先说一下进程。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它系统资源组成。linux中通过pcb(进程控制块,一个task_struct结构体)来动态描述程序运行。
然后举个工厂的例子:工厂中偶很多工人加工产品。这个工厂就像是进程,需要完成很多不同任务,而真正干事情的不是工厂而是工厂里的工人,这里的工人就相当为线程。在实际程序运行中,线程才是真正调度程序运行的单元,进程是资源的载体。

总结:线程是进程中的一条执行流(通过轻量级进程来实现),负责一段代码的执行调度,在Linux下线程这个执行流程是通过进程(pcb)来实现的(pcb–>进程控制块,linux下是一个task_struct,是程序运行的动态描述),一个进程中可以有多个线程(pcb),这些线程共享进程的大部分资源,相比于pcb比较轻量化,因此被称作轻量化进程。因此,在linux下线程就是轻量级进程。(故linux下只有轻量级进程,无线程。)
进程是系统进行资源分配的基本单元,
线程是系统进行调度运行的基本单元。

举个例子理解一下:比如系统要同时完成三个任务,如下图,可以用多个进程(pcb)来分别执行不同任务的代码。但是这样的话除了要完成的任务的代码和资源不同,其它部分资源被多次开辟会存在大量的资源浪费,并不可取。
在这里插入图片描述
采用多线程来完成这三个任务的话,如下图,可以想象为是将上面的三个pcb资源整合为一个大的pcb(其实只有一个pcb),这个大的pcb中包含了完成这三个任务所需的资源。这个大的pcb就是进程,而之前三个独立的pcb就相当是线程,分别完成不同任务。而这个大的pcb可以同时完成这三个任务(并发运行),这就节省了很多重复资源的开辟和线程间切换调度成本。
简单理解就是:线程就是完成一个任务的pcb(轻量级进程),而进程就是包含了很多个这些小的pcb的大的pcb,能同时完成多个任务。
在这里插入图片描述

线程,进程和程序的区别和联系参考这里

1.2线程间的独有与共享

独有:标识符,栈 ,寄存器(程序计数器,上下文信息),信号屏蔽字(防阻塞),errno…
共享:虚拟地址空间(代码段,数据段),IO信息,信号的处理方式,工作路径…

1.3线程间的通信方式:

  1. 包括进程间的通信方式(管道,共享内存,消息队列,信号量)
  2. 全局变量
  3. 函数传参

1.4多进程与多线程处理多任务时的优缺点

多线程优点:

  1. 线程间通信比进程的通信方式多,更加灵活。
  2. 线程的创建和销毁成本比较低。(由于 线程共享了pcb的大部分资源,对于共享的资源不必重复创建和销毁,只额外创建和销毁自己独有的资源)
  3. 同一进程中的线程间切换调度成本更低。

多进程优点:

  1. 健壮性和稳定性高,独立性强(进程退出则所以线程退出)。

多进程应用场景:适用于对于主程序安全性要求比较高哦的场景使用多进程(shell,服务器等,子进程崩了不会影响到父进程)。其它场景使用多线程更好。
在多任务处理中,执行流并不是越多越好,Cpu资源存在上限,执行流多了反而会增加线程间切换调度成本。

线程间的切换调度算法:FIFO,RR,多级反馈。

2.线程控制

linux下实际上并没有向上提供用于线程控制的接口,因此大佬们针对系统调用接口进行封装,在上层用户态封装了线程库,提供了线程控制的各个接口(thread库函数),通过这些接口操作线程。
在这里插入图片描述

2.1创建

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                     void *(*start_routine) (void *), void *arg);

参数:
thread:线程Id,操作句柄(地址)。(每个线程在进程虚拟地址空间中都有一个属于自己相对独立的空间,保存自己独有的资源。)
attr:设置线程属性,设置为NULL即可。
第三个参数void *(*start_routine) (void *)为线程入口函数(回调函数),这个函数运行完毕则线程结束。
arg:传给线程入口函数的参数。无参数传递则NULL即可。传入的参数会在void *(*start_routine) (**void **)中的用void来接收。
返回值:成功返回 0;失败返回非0值(表示错误编号)。

说一条命令可以查看执行流(轻量级进程(LWD)): ps -ef -L | grep “…”

2.2 退出

线程入口函数运行完毕则线程退出。

线程的退出有以下几种方式:

  1. 在线程入口函数中return则可退出线程。(main中return 则表示退出进程)。
  2. 在任意位置调用接口(谁调用谁退出):void pthread_exit(void *retval),其中参数retval为线程的返回值,可设置为NULL。
#include <pthread.h>
void pthread_exit(void *retval);
int pthread_cancel(pthread_t thread);
  1. 在任意位置调用接口(谁调用谁退出):int pthread_cancel(pthread_t thread),其中参数thread为线程Id(操作句柄)。这个接口的功能为取消线程,线程会被迫退出(可能还没有运行完),线程的返回值是没有意义的。

问题:一个线程退出会不会影响其他线程?

线程不像进程,一个进程中的线程之间是没有父子之分的,都是平级关系。即线程都是一样的, 退出了一个不会影响另外一个。
主线程的退出并不会影响进程以及其它线程,只有所有线程退出,进程才会退出。主线程退出后子线程的状态依赖于它所在的进程,如果进程没有退出的话子线程依然正常运转。如果进程退出了,那么它所有的线程都会退出,所以子线程也就退出了。

2.3 等待

等待一个进程,获取退出线程的返回值,回收其资源。
在创建一个线程时会有一个默认属性—>分离属性,默认值为joinable,处于joinable状态的线程退出后不会自动释放资源,需要被等待。

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

参数:
thread:指定线程的ID
retval:获取线程返回值(返回值为void*,故获取返回值要传入二级指针)。

2.4 分离

将指定线程的分离属性设置为detach状态,处于detach状态的线程推出后会自动释放资源,不需要被等待。

#include <pthread.h>
int pthread_detach(pthread_t thread);

参数thread:线程ID
一般不关注这个函数的返回值。

常会在线程的入口函数中分离自己,eg:在入口函数中使用:pthread_detach(pthread_self());其中pthread_self()为获取线程自身ID.
若线程已经被分离之后又进行pthread_join()等待则会报错。

对于一个线程,我们要么等待其退出,要么就要将其分离,这样才能使其退出后资源被回收。
如果对线程的返回值不关心,并且也不想等待线程退出时则将线程分离。

2.5练习-线程的创建使用

创建两个线程交替打印我是线程A和我是线程B。


  #include <unistd.h>                                                              
  #include <stdio.h>
  #include <pthread.h>
  #include <utime.h>
                               
             
void* entry_A(void* arg){     //线程A入口函数
    while(1){      
      printf("我是线程A\n");
      sleep(1);     
    }  
    return NULL;
  }             

void* entry_B(void* arg){     //线程B入口函数
    while(1){    
      printf("我是线程B\n");    
      sleep(1);    
    }    
    return NULL;    
  }    
      
  int main()    
  {    
    pthread_t tid_A,tid_B;    
    int ret;    
    ret =pthread_create(&tid_A,NULL,entry_A,NULL);    
    if(ret!=0){    
      perror("pthread error \n");    
    }    
      
    pthread_create(&tid_B,NULL,entry_B,NULL);    
    if(ret!=0){    
      perror("pthread error \n");    
    }    
      
    pthread_join(tid_A,NULL);    
    pthread_join(tid_B,NULL);    
    return 0;    
  } 

结果

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值