【Linux操作系统】多线程控制(创建,等待,终止、分离)

目录

  • 一、线程与轻量级进程的关系
  • 二、进程创建
    • 1.线程创建
      • 线程创建函数(pthread)
      • 查看和理解线程id
      • 主线程与其他线程之间的关系
  • 三、线程等待(回收)
  • 四、线程退出
    • 线程退出情况
    • 线程退出方法
  • 五、线程分离
  • 线程的优点
  • 线程的缺点

一、线程与轻量级进程的关系

首先我想问一个问题,Linux中有没有真线程呢? 答案是没有,Linux中只有轻量级进程

但是用户不知道“轻量级进程”,认为只有进程和线程。因此,Linux系统中不会有与线程相关的系统调用,只有轻量级进程的系统调用

Linux系统为了能让用户进行正常的使用Linux线程,Linux设计者在用户与内核之间设计了一个 pthread库—原生线程库

**作用是将轻量级进程的系统调用进行封装,转成线程相关的接口语义提供给用户,让用户感觉自己使用的是线程,但实际上底层是轻量级进程 **,所以我们平时在Linux中使用线程必须带上这个库, 不过要注意的是这个库并不属于LInux内核,只要是库它就是在用户级实现的,因此有许多人将Linux的线程称作“用户级线程”,所有线程的实现都是在 用户级实现的

二、进程创建

1.线程创建

线程创建函数(pthread)

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
  • thread:返回线程ID
  • attr:设置线程的属性,attr为NULL表示使用默认属性
  • start_routine:函数地址,线程启动后要执行的函数
  • arg:传给线程启动函数的参数
  • 返回值:成功放回0,失败返回错误码

举例:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>void *newthreadrun(void *args)
{while (true){std::cout << "I am new thread, pid: " << getpid() << std::endl;sleep(1);}
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, newthreadrun, nullptr);while (true){std::cout << "I am main thread, pid: " << getpid() << std::endl;sleep(1);}
}

有个注意事项就是,如果我们创建线程传递的是 类成员函数 ,那么就需要将我们的类成员函数声明为static函数,因为如果类成员函数的参数中默认会有一个this指针,将类成员函数声明为static函数,这个成员函数就没有this指针了,否则就会造成匹配错误

查看和理解线程id

使用 ps -aL 查看

在这里插入图片描述
当我们使用 ps -aL 查看进程时我们会发现除了我们熟知的PID,还有一个陌生的LWP

如果这个进程是单进程的话,这个PID和LWP是一样的
如果这个进程是多线程的话,这个LPW代表不同线程(轻量级进程(light weight process))LWP
其中这个PID是主线程的ID

pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事,前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一表示该线程
pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的

线程库NPTL提供了pthread_ self函数,可以获得线程自身的ID:

pthread_t pthread_self(void);

主线程与其他线程之间的关系

  1. 主线程与其他线程谁先运行?

这个答案是不确定的,由调度器决定

  1. 主线程退出,其他线程继续运行还是退出?

主线程退出,就等同于这个进程退出了,而进程是承担分配系统资源的基本实体,进程退出了,进程所拥有的内部资源也应该被释放,也包括内部的执行流等,所以只要主线程退出了,所有进程都要退出

  • 这也意味着我们的主线程需要最后结束

三、线程等待(回收)

前面我们学过,进程在退出时需要回收它(wait),否则就会变成僵尸进程,而线程同样如此,线程也需要被回收(wait),否则也会造成内存泄漏问题

线程等待函数 :pthread_join

int pthread_join(pthread_t thread, void **value_ptr);
  • thread:线程id
  • value_ptr:它指向一个指针,后者指向线程的返回值
  • 返回值:成功返回0;失败返回错误码

调用该函数的线程将挂起等待,直到id为thread的线程终止。

thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的:

  • 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值
  • 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数 PTHREAD_ CANCELED。
  • 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数
  • 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数

四、线程退出

线程退出情况

线程退出无非三种情况:

  1. 代码跑完,结果对
  2. 代码跑完,结构错
  3. 代码出异常

重点是出异常情况:

如果在多线程中,任意一个进程出现异常,都会导致整个进程退出,因此有些人说多线程代码往往健壮性不好

线程退出方法

  • 使用return

从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。

  • 使用pthread_exit函数

线程可以调用pthread_ exit终止自己,类似于进程退出的exit

void pthread_exit(void *value_ptr);

无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)

需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了

  • 使用pthread_cancel函数

取消一个执行中的线程

int pthread_cancel(pthread_t thread);
  • thread:线程ID
  • 返回值:成功返回0;失败返回错误码

五、线程分离

默认情况下,新创建的线程是joinable的,也就是说,在线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏,导致类似僵尸进程的事件

但如果我们的主线程并不关心其他线程的返回值,join它是一种负担,这个时候,我们可以告诉系统,当该线程退出时,自动释放该线程资源,也就是说,我们可以将这个线程分离出去,可以说使该线程与主线程达到真正的并行

不过所谓的分离只是线程的一种工作状态,并不是说页表、进程地址空间等分离了,底层依旧属于同一个进程,因此当主线程退出时,分离线程还是会跟着退出,只是不需要等待了

线程并行方法:

  • 在主线程分离其他线程
int pthread_detach(pthread_t thread);
  • 在该线程中分离线程
pthread_detach(pthread_self());

举例:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <pthread.h> 
void* thread_run(void* arg)
{pthread_detach(pthread_self());printf("%s\n", (char*)arg);return NULL;
}
int main(void)
{pthread_t tid;if (pthread_create(&tid, NULL, thread_run, "thread1 run...") != 0) {printf("create thread error\n");return 1;}int ret = 0;sleep(1);if (pthread_join(tid, NULL) == 0) {printf("pthread wait success\n");ret = 0;}else {printf("pthread wait failed\n");ret = 1;}return ret;
}

线程的优点

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

线程的缺点

  • 性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型
线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的 同步和调度开销,而可用的资源不变。

  • 健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了
不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。

  • 缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。

  • 编程难度提高

编写与调试一个多线程程序比单线程程序困难得多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/485259.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序 —— Day1

组件 — view和scroll-view view 类似于HTML中的div&#xff0c;是一个块级元素 案例&#xff1a;通过view组件实现页面的基础布局 scroll-view 可滚动的视图区域&#xff0c;用来实现滚动列表效果 案例&#xff1a;实现纵向滚动效果 scroll-x属性&#xff1a;允许横向滚动…

快速构建NLP理论知识体系

NLP理论知识体系 一句话解释NLPNLP模型及原理简述1、Rag 一句话解释NLP 如果我们要实现机器翻译、情感分析、问答系统、文本摘要、聊天机器人、构造智能化的辅助文件填写模板&#xff0c;NLP可以通过现成的模型对输入的语音、文字、图片进行处理&#xff08;分词、标词性、去停…

Kafka的消费消息是如何传递的?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka的消费消息是如何传递的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Kafka的消费消息是如何传递的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka 的消息传递是通过 消费者&#xff08…

shell脚本实战案例

文章目录 实战第一坑功能说明脚本实现 实战第一坑 实战第一坑&#xff1a;在Windows系统写了一个脚本&#xff0c;比如上面&#xff0c;随后上传到服务&#xff0c;执行会报错 原因&#xff1a; 解决方案&#xff1a;在linux系统touch文件&#xff0c;并通过vim添加内容&…

Android 使用 Canvas 和 Paint 实现圆形图片

学习笔记 效果展示: 全部代码: public class YuanActivity extends AppCompatActivity {private ActivityYuanBinding binding;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 通过 DataBinding 获取布局文件binding …

敖汉宝塔油页岩露天矿山安全自动化监测

1. 项目简介 本次项目位于内蒙古自治区赤峰市敖汉旗宝国吐乡大青山村&#xff0c;地理位置好。主营许可经营项目&#xff1a;无一般经营项目&#xff1a;页岩油生产&#xff1b;页岩油、润滑油、建筑材料&#xff08;不含油漆&#xff09;销售等单位规模1-20人&#xff0c;单位…

fedora下Jetbrains系列IDE窗口中文乱码解决方法

可以看到窗口右部分的中文内容为小方块。 进入 Settings - Appearance & Behavior - Appearance - Use custom font : Note Sans Mono CJK SC &#xff0c;设置后如下图&#xff1a;

LeetCode题练习与总结:删除二叉搜索树中的节点--450

一、题目描述 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。 一般来说&#xff0c;删除节点可分为两个步骤&am…

Python_Flask03

这篇文章主要介绍的是数据库的增删改查操作&#xff0c;无多余好说的。 from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from flask_migrate import Migrateapp Flask(__name__)# 本地基础信息的主机名 HOSTNAME "127.0…

我国基本比例尺地形图介绍

目录 1.前言2.大中小比例尺划分3.使用的投影4.使用3度带6度带&#xff1f;5.详细介绍1:100万地形图1:50万地形图1:25万地形图1:10万地形图1:5万地形图1:2.5万地形图1:1万地形图1:5000地形图 6.总结 1.前言 本文搜集整理了我国国家基本比例尺地形图的情况&#xff0c;共11种&…

离线安装ollama到服务器

搜了很多教程不满意,弄了半天才弄好&#xff0c;这里记录下&#xff0c;方便以后的人用&#xff0c;那个在线下载太慢&#xff0c;怕不是得下载到明年。 一.从官网下在liunx版的tgz安装包 Releases ollama/ollama (github.com) 查看自己的服务器信息&#xff08;参考 https:/…

Face2QR:可根据人脸图像生成二维码,还可以扫描,以后个人名片就这样用了!

今天给大家介绍的是一种专为生成个性化二维码而设计的新方法Face2QR&#xff0c;可以将美观、人脸识别和可扫描性完美地融合在一起。 下图展示为Face2QR 生成的面部图像&#xff08;第一行&#xff09;和二维码图像&#xff08;第二行&#xff09;。生成的二维码不仅忠实地保留…

WHLUG丨deepin、华中科技大学开放原子开源俱乐部、 RustSBI 和清华大学开源操作系统训练营共话开源新生代成长之路

2024年11月30日下午&#xff0c;由 deepin&#xff08;深度&#xff09;社区联合华中科技大学开放原子开源俱乐部、 RustSBI 开源社区和清华大学开源操作系统训练营共同举办的WHLUG&#xff08;武汉Linux用户组&#xff09;线下沙龙在华中科技大学成功举办。 本次活动聚集了50余…

排查bug的通用思路

⭐️前言⭐️ APP点击某个按钮没有反应/PC端执行某个操作后&#xff0c;响应较慢&#xff0c;通用的问题排查方法: 从多个角度来排查问题 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评…

Uniapp的App环境下使用Map获取缩放比例

概述 目前我试过的就是你用vue后缀是拿不到比例的你可以用nvue当然uniapp的uvue应该是更加可以的我使用的是高德所以你得在高德的后台声请原生的Android的key才可以如果是vue3的开发模式的话不用使用this来获取当前对象使用scale对象来接受和改变缩放比例会比较友好然后直接走…

如何利用Java爬虫获得商品类目

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。获取和分析数据的能力对于任何希望在市场上保持竞争力的企业来说都是至关重要的。对于电子商务平台和市场研究公司而言&#xff0c;获取商品类目数据尤为重要&#xff0c;因为这些数据可以帮助他们更好地理解市场…

筑起厂区安全--叉车安全防护装置全解析

在繁忙的工业生产领域中&#xff0c;叉车作为搬运工&#xff0c;穿梭于仓储与生产线之间。然而&#xff0c;叉车的高效运作背后&#xff0c;也隐藏着诸多安全风险&#xff0c;尤其是在那些空间狭小、物流繁忙的环境中。为了降低这些潜在的危险&#xff0c;叉车安全防护装置便成…

AI新动向:豆包文生图升级,文心一言领先市场

在今日的AI资讯中&#xff0c;我们关注到了几个重要的行业动态&#xff0c;其中包括字节跳动AI助手豆包的功能升级&#xff0c;以及百度文心一言在生成式AI市场的领先地位。 字节跳动旗下的智能AI助手豆包近期对其文生图能力进行了显著提升&#xff0c;用户现在可以通过一键操…

【深度学习】手机SIM卡托缺陷检测【附链接】

一、手机SIM卡托用途 SIM卡托是用于固定和保护SIM卡的部件&#xff0c;通过连接SIM卡与手机主板的方式&#xff0c;允许设备访问移动网络&#xff0c;用户可以通过SIM卡进行通话、发送短信和使用数据服务。 二、手机SIM卡托不良影响 SIM卡接触不良&#xff0c;造成信号中断&…

PDF文件打开之后不能打印,怎么解决?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…