Linux多线程理解---(线程概念,线程控制)

目录

线程概念

线程之间的独有与共享

多线程与多进程的优缺点分析

线程控制

线程创建

线程终止

线程等待

线程分离


​​​​​​​

线程概念

在以前我们学习进程的时候,进程就是一个pcb,是一个task_struct结构体,里面有很多描述信息实现操作系统对程序运行的管理

在我们学习到线程后,发现线程是进程的一条执行流,在linux下,程序调度是通过pcb完成的,pcb是linux下的执行流,所以也可以认为linux下的pcb是一个线程,只不过linux下通常不谈线程,而叫做轻量级进程

  • 进程:是一个程序动态的运行,一个程序运行的描述,cpu资源分配的基本单位
  • 线程:是一个进程中的执行流,执行程序中的某段代码,cpu执行调度的基本单位

所谓轻量化进程就是一个进程中可以存在多个pcb,这些pcb共用一个虚拟地址空间 每一个线程都是进程中的一个执行流,因此多个执行流可以共同工作,这些pcb合在一起就是线程组,也可以将进程理解为一个线程组.

线程之间的独有与共享

共享

虚拟地址空间:数据段代码段

信号处理方式

IO信息

用户ID/组ID工作路径......

独有

  • 栈:避免调用栈混乱
  • 寄存器:保存运行信息
  • 线程ID---线程的标识符:用于区分不同线程
  • 信号屏蔽字:特殊线程执行任务时不希望被某个信号打断
  • erron:全局变量errno可以存放错误原因,当错误发生时,函数的返回值是可以通过非法值来提示错误的发生。
  • 优先级:线程调度的优先级

多线程与多进程的优缺点分析

优点

多线程

  1. 线程间通信非常灵活(包含进程间通信方式在内,也可以通过全局变量或者传值)
  2. 线程的创建与销毁成本更低(线程资源大多共享)
  3. 线程间的切换调度成本稍低(很多数据不需要切换)

 多进程

独立性高,稳定性强

多线程和多进程的优缺点是互补的.

共同优点:多任务使用多执行流处理的优点,都可以提高效率

CPU密集型程序:程序几乎都是cpu数据运算,执行流并不是越多越好,多了反而增加切换调度成本CPU密集型程序的执行流个数一般是cpu核心数+1,防止切换调度增加成本

IO密集型程序:程序中几乎都是IO操作

IO操作:等待IO就绪,数据拷贝

线程控制

在linux中系统没有直接提供线程的操作接口,不过在上层上封装实现了一套线程库.

线程控制通过线程创建->线程终止->线程等待->线程分离来控制

线程创建

实现在用户态创建一个线程,但是linux下程序调度只能通过pcb完成,因此在内核创建了一个新的pcb出来.这时我们上层创建的线程叫做用户态线程,内核的pcb叫做轻量级进程

本质上就是通过在内核创建了一个轻量级进程来实现的

接口

int pthread_create()

参数:

  • pthread_t *tid:用于获取上层线程id tid实际上是创建线程后,线程有自己独立的一块空间的首地址
  • pthread_attr_t *attr 用于设置线程属性,通常置NULL
  • void *(*thread_routine)(void *arg);线程入口函数
  • void *arg 传递给线程入口函数的参数
  • 返回值:成功返回0,失败返回非0值.
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void *thread_entry(void *arg)
{
  while(1)
  {
    printf("i am new thread!! %s\n",(char*)arg);
    sleep(1);
  }
  return NULL;
}
int main()
{
  pthread_t tid;
  char buf[32]="快要下课了!\n";
  int ret=pthread_create(&tid,NULL,thread_entry,(void*)buf);
  if(ret!=0)
  {
    printf("thread create error:%s\n",strerror(ret));
    return -1;
  }
  while(1)
  {
    printf("i am main thread!\n");
    sleep(1);
  }
  return 0;

}

 LWP是轻量级进程id,两者不同,他们有相同的PID,NLWP是轻量级进程数量,都是2;

线程终止

线程终止就是退出线程

  • 在线程入口函数中return,(main函数return退出的是进程);
  • 在任意位置调用void pthread_exit(void *retval)
  • 在任意位置调用 int_pthread_cancel(pthread_t tid)
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void *thread_entry(void *arg)
{
  while(1)
  {
    printf("i am new thread!! %s\n",(char*)arg);
    sleep(1);
  }
  return NULL;
}
int main()
{
  pthread_t tid;
  char buf[32]="快要下课了!\n";
  int ret=pthread_create(&tid,NULL,thread_entry,(void*)buf);
  if(ret!=0)
  {
    printf("thread create error:%s\n",strerror(ret));
    return -1;
  }
  printf("i am main thread");
  while(1)
  {
    printf("i am main thread!\n");
    sleep(3);
    pthread_exit(NULL);
  }
  return 0;

}
[dev@localhost pthread]$

注意,主线程退出子线程并不退出

线程等待

等待一个指定的线程退出,获取这个线程的退出返回值,释放资源.默认情况下,如果一个线程退出

,如果不等待也会造成资源泄露

int pthread_join(pthread_t tid,void **retval)

tid表示要等待哪个线程退出

retval:是一个void*空间的地址,用于接收线程返回值

void *(*thr_entry)(void *arg)

注意:默认情况下线程退出,为了保存自己的退出返回值,因此线程占用的资源在退出后也不完全被释放,需要被等待

线程等待也不仅仅是因为为了释放资源,避免资源泄露而等待

还有一种,必须等到某个线程处理完成后得到结果才能继续往下处理.

还有一种,等到某个或者所有线程退出后再运行.

线程分离

当我们不关心一个线程的返回值的时候,又不需要等待线程退出才能往下运行,这时候等待会导致性能降低,这时候等待就不合适了,但是不等待又会资源泄露,这时候线程分离就极其重要了

在设计线程的时候,线程有很多属性,其中有一个分离属性,分离属性默认值-JOINABLE,表示线程退出后不会自动释放资源,需要被等待;

如果将线程的分离属性设置为其他值-DETACH,这时候则线程退出后将不需要被等待.

退出后自动释放资源,等待会出错.

int pthread_detach(pthread_t pthread)

pthread_self()获取调用线程自己的tid;

一个线程不关心返回值,也不想等待,这种线程适合被分离

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值