Linux多线程

“过好每一天,就是对无奈人生最好的报复。” --朱德庸

在了解完Linux中信号的内容之后,我们接下来对多线程内容进行讲述,这一模块内容较长,请耐心。

对于多线程内容,我们将从接下来这几部分内容来讲述:线程概念,线程控制,线程安全和线程应用。

目录

1.线程概念

1.1内容

1.2线程和进程

1.3多线程在同一进程的执行特征

2.线程控制

2.1线程创建

2.2线程终止

2.2.1线程入口函数return

2.2.2退出当前线程

2.2.3退出指定线程

2.3线程等待与分离

2.3.1线程等待

2.3.1线程分离

1.线程概念

1.1内容

首先我们需要清楚的基本概念是,线程是进程中的一个执行流程,是CPU进程调度执行的基本单元,调度一段代码便是通过线程来完成的。(进程是系统分配资源的基本单元)

而在Linux中pcb是程序运行过程中的描述,因此在Linux下的线程是通过pcb来实现的。

则多进程和多线程的理解大致应该是:当我们需要完成一个多任务目标项时,多进程是编写多个程序对应多个任务,然后每个程序对应的pcb来调度执行各自的任务;而多线程是对于同一个程序而言,将程序内容划分成多个模块来对应多个任务,然后创建每个模块的pcb来调度各自的任务(Linux中一个进程允许有多个pcb)。

那么对于多进程而言,占用系统资源更多(创建了多个进程),但是运行稳定(进程之间相互独立,互不影响);对于多线程而言,占用系统资源较少(将一个程序划分多个模块),但是运行容易崩溃,书写代码需多加注意(同一个程序中:一荣俱荣,一损俱损)。

最后读者引用以下apue中对于线程的讲述:

我们可以很明显看出,在Linux中线程功能便是将一个进程设计成为同一时间内可完成多个任务。也就是上述内容中笔者所提到的:将同一个程序设计分为多个模块,每个模块对应不同任务。

1.2线程和进程

我们再来总结一下,进程和线程的区别:

  • 进程是系统进行资源分配的基本单元,每运行一个程序,操作系统便分配一次程序运行所需的资源;
  • 线程是CPU进行执行调度的基本单元,在Linux中是通过pcb来实现的,其中一个进程允许有多个pcb,因此也被称为轻量级进程lwp。

对于多进程:稳定,不易崩溃;

对于多线程:线程间通信更加灵活(共享虚拟地址空);创建和销毁成本更低(线程之间很多资源共享,单独创建内容较少);同进程的线程调度成本更低(CPU上的快表信息,页表指针……都不需要替换)。

那么,当对程序的安全性和稳定性要求大于资源和性能要求时,我们便需要使用多进程来构建;反之,我们使用多线程。

1.3多线程在同一进程的执行特征

多线程是设计在同一个进程之中来完成不同的任务,那么为了避免线程执行不混乱,我们必须明确线程在进程之中的特征对其加以约束和控制。

首先从具体实现上而言,每个线程调度执行的就是一个函数。当我们市容vfork接口创建子进程之后,父子进程公用同一块虚拟地址空间,为了避免运行时可能出现的栈混乱,因此父进程会阻塞直到子进程替换或退出。

然后当多进程之间出现混乱时,我们可以将所有可能混乱的地方,给每个线程都拷贝一份,即手动实现线程之间的相互独立。

最后线程之间的独有信息有:标识符,栈,上下文数据,信号屏蔽字和errno……线程之间的共享信息有:虚拟地址空间,文件描述符,信号处理方式,工作路径,用户ID,组ID……

2.线程控制

线程的控制我们将从创建,终止,等待和分离这四部分讲述。不过在了解线程控制之前,我们需要了解的是,Linux中并不存在线程的直接内容,线程是我们在上层提出的概念,而Linux操作系统并没有单独的内容来对其进行实现。

也正如我们线程概念中提到的内容,Linux中的线程对应的是底层中的轻量级pcb,即lwp。所以Linux操作系统并未直接提供相应的系统调用接口供我们来实现线程控制,我们有关线程控制的所有操作都是前人封装而成的库函数。

2.1线程创建

int pthread_create(pthread_t *tid, pthread_attr *attr, void* (*routine)(void*), void *arg);

pthread_create函数的作用:创建一个线程,指定这个线程需要运行的函数routine,并且给该函数传入一个数据arg。

其中,tid:传入一个pthread_t类型变量的空间地址,用于接收线程ID--线程的操作句柄;attr:线程属性,通常制NULL; routine:函数指针,传入线程入口的函数地址,该线程调度执行的便是此函数;arg:给routine线程入口函数传入的参数。

返回值:创建线程成功则返回0,失败则返回非0值(错误编号)。

按照以往习惯,我们来通过书写代码进行一个说明:

书写完成之后,我们进行执行:

会报错,但是对于代码中的头文件pthread.h我们已经添加,为什么还会产生在mian中pthread_create未定义的情况。这是因为pthread的内容是我们连接第三方库来实现的,所以我们在执行中需要在gcc pcreate.c -o pcreate后加上-lpthread。

再次执行:

就不会产生错误啦~。而且我们能很直观看出二者好似在交替运行,但实际上并非如此,对于线程执行的优先级是由CPU调度决定了。这是我们在进程概念中提到的内容:CPU分时机制,即CPU的调度是通过时间片的分配来决定的。

所以当我们取消sleep之后,我们可以发现在线程自己的时间片之中,自身的内容会实现很多次。(结果太长,不便于展示,望读者自己动手)

2.2线程终止

线程的终止即是退出一个线程的运行,线程调度运行的是创建时所传入的routine函数,所以当routine函数退出后,线程也会退出。

线程终止的三种方式:

2.2.1线程入口函数return

当入口函数被return退出之后,对应的线程也便结束。不过需要注意的是:main中return退出的会是主进程,而不仅是主线程。

2.2.2退出当前线程

void pthread_exit(void* retval);

pthread_exit接口用于退出当前线程,可在线程的任意位置被调用,其中retval用于设计线程退出的返回值。

2.2.3退出指定线程

int pthread_cancel(pthread_t tid);

pthread_cancel接口用于退出指定进程,可在线程的任意位置被调用,其中tid便是会被退出的线程标识。注意被退出的线程其返回值会不可控,不能用其原本的退出返回值来判断。

2.3线程等待与分离

在了解线程等待与分离之前,我们需要了解两部分知识点。首先便是,当我们使用线程退出接口退出主线程后,我们可以发现其他我创建得到的线程依旧会照常运行。如下图展示:

并且在程序运行中,我们查看进程信息:

我们可以发现,当我们设计主线程退出时,其资源并没有被完全释放,而其是一种do_exit状态。 

那么第二点我们需要了解的内容便是,线程退出之后,该线程的资源也并不会立即完全被释放,因为我们需要保存其返回值。(值得注意的是:所有的线程退出之后,则进程退出释放资源;当进程打断进行退出,则会想退出所有的线程。)

了解完上述内容之后,我们来讲述线程等待和分离的内容:

2.3.1线程等待

线程等待便是:等待指定的线程退出,获取线程的返回值,回收退出线程的所有资源。

int pthread_join(pthread_t tid, void **retval);

pthread_join接口用于线程等待,用于阻塞线程,等待tid线程执行完毕后,再执行接下来的线程。

其中,tid便是:要等待退出的指定线程tid;retval:用于获取线程的退出返回值。(因为线程退出返回值时void*类型,因此需要传入指针变量的地址,即二级指针)

返回值:成功返回0,失败返回非0(错误编号)。

通过代码来展示:

执行结果为:

可以很直观的看出,待entry线程运行结束之后,main主线程才开始执行。(真正操作时,大家需要格外注意线程中变量的生命周期,防止局部变量走出函数被释放其余线程访问错误情况。)

2.3.1线程分离

在线程属性中,存在一个格外的属性称作分离属性,默认值是joinable状态,表示线程退出之后,不会自动释放资源,需要被其他线程等待。

但是有些时候我们并不关心某个线程的返回值,更不期望等待它的退出,则此时我们可以将其状态设置为detach状态。表示该线程退出后,其资源会立即被释放,不需要被等待。

int pthread_detach(pthread_t tid);

pthread_detach接口便用于设计对应的线程属性为detach属性。其中,tid则是设计分离属性的detach的线程。

返回值:成功返回0,失败返回非0(错误编号)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中的多线程实际上是通过进程来模拟实现的。在Linux中,多个线程是通过共享父进程的资源来实现的,而不是像其他操作系统那样拥有自己独立的线程管理模块。因此,在Linux中所谓的“线程”其实是通过克隆父进程的资源而形成的“线程”。这也是为什么在Linux中所说的“线程”概念需要加上引号的原因。 对于Linux中的线程,需要使用线程库来进行管理。具体来说,Linux中的线程ID(pthread_t类型)实质上是进程地址空间上的一个地址。因此,要管理这些线程,需要在线程库中进行描述和组织。 由于Linux中没有真正意义上的线程,因此线程的管理和调度都是由线程库来完成的。线程库负责创建线程、终止线程、调度线程、切换线程,以及为线程分配资源、释放资源和回收资源等任务。需要注意的是,线程的具体实现取决于Linux实现,目前Linux使用的是NPTL(Native POSIX Thread Library)。 总结来说,Linux中的多线程是通过进程来模拟实现的,线程共享父进程的资源。线程的管理和调度由线程库完成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux —— 多线程](https://blog.csdn.net/sjsjnsjnn/article/details/126062127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值