Linux多线程之线程控制

(。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~icon-default.png?t=N7T8https://blog.csdn.net/ky233?type=blog

点个关注不迷路⌯'▾'⌯

目录

一、pthread_crate

二、pthread_join

三、pthread_exit和pthread_cancel

四、关于线程id的探索

五、pthread_self

六、线程的局部存储

七、线程调用execl

八、分离线程


一、pthread_crate

大部分上篇文章已经详细说过了,这里仅做补充

在多进程中,我们不知道父子进程谁先运行,同样的,多线程也是随机的

线程异常的情况下

#include <iostream>
#include <pthread.h>
#include <unistd.h>using namespace std;void *threadRoutine(void *args)
{while (1){cout << "新线程:" << (char *)args << "running..." << endl;sleep(1);int a = 100;a/=0;}
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while (1){cout << "main线程:"<< "running..." << endl;sleep(1);}
}

这个时候我们就会发现,程序异常了,出现了8号信号,所以我们可以得出结论

线程一旦异常,都可能导致进程整体退出。

二、pthread_join

线程在创建并执行的时候,线程也是要进行等待的!如果主线程不等待,即会引起类似于进程的僵尸问题,导致内存泄漏!

int pthread_join(pthread_t thread,void **retval)
  • 参数一:线程id
  • 参数二:输出型参数,用于获取次线程的退出结果,如果不关心,可以传递 nullptrr
  • 返回值:失败返回错误码,成功为0

在调用了之后,我们的主线程会默认的阻塞,并等待新线程退出

#include <iostream>
#include <pthread.h>
#include <unistd.h>using namespace std;void *threadRoutine(void *args)
{int i = 0;while (1){cout << "新线程:" << (char *)args << "running..." << endl;sleep(1);if (i++ == 10)break;}cout<<"新线程退出"<<endl;return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");pthread_join(tid, nullptr);cout << "主线程正在等待...主线程成功退出" << endl;
}

在新线程退出的时候,我们可以返回特定的值,但是需要强转一下,如(void*)10,那么这是返回给谁呢?答案是谁等你就给谁,一般是给主线程的,所以我们可以这样写来获取新线程的返回值

void *threadRoutine(void *args)
{int i = 0;while (1){cout << "新线程:" << (char *)args << "running..." << endl;// sleep(1);if (i++ == 10)break;}cout << "新线程退出" << endl;return (void *)10;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");void *ret = nullptr;pthread_join(tid, &ret);cout << "主线程正在等待...主线程成功退出,新线程的返回值:" << (long long)ret << endl;
}

线程等待是不需要关心是否有异常的,因为新线程崩溃了,主线程也崩溃了

三、pthread_exit和pthread_cancel

线程终止的话是不能用exit的,这个是终止进程的,一旦调用,exit直接把进程终止了

void pthread_exit(void *retval);
  • 参数一:用于传递线程退出时的信息

或者我们可以用这个函数进行线程取消

int pthread_cancel(pthread_t thread)
  • 参数一:线程id
  • 如果想取消谁调用这个函数填入对应的线程id就可以了
  • void *threadRoutine(void *args)
    {while (1){cout << "新线程:" << (char *)args << "running..." << endl;sleep(1);}cout << "新线程退出" << endl;
    }
    int main()
    {pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");int count=0;while (1){cout << "main线程:"<< "running..." << endl;sleep(1);count++;if(count==5) break;}pthread_cancel(tid);cout<<"线程取消"<<tid<<endl;void *ret = nullptr;pthread_join(tid, &ret);cout << "主线程正在等待...主线程成功退出,新线程的返回值:" << (long long)ret << endl;
    }

这其中有几个细节需要注意

  •  线程被取消join的时候,退出码是-1,
  • 一般是在保证新线程运行起来了,后来不需要了才需要用这个接口
  • 不要用这个接口,用新线程取消主线程 

四、关于线程id的探索

当我们打印一个线程id之后可以发现,线程id是这个样子的,是一个非常大的整数

原因是因为它本质是一个地址!

上篇文章说过pthread会个线程提供一个用户层的栈结构,这个线程id就是栈结构的起始地址,对应的就是在库内部对应的相关属性的起始地址。

对于主线程来说直接用内核级栈结构,对于新线程来说则用的是共享区内部提供的用户层栈结构,这样就可以保证每个线程的栈是独立的了,并且还不和但执行流的进程相冲突

五、pthread_self

这个接口很简单,就是哪个线程掉的我,直接就获取对应线程的线程id

void *threadRoutine(void *args)
{while (1){cout << "新线程:" << (char *)args << "running..." << pthread_self() << endl;sleep(1);}cout << "新线程退出" << endl;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");printf("%lu,%p", tid, tid);cout << endl;int count = 0;while (1){cout << "main线程:"<< "running..." << pthread_self() << endl;sleep(1);count++;if (count == 5)break;}pthread_cancel(tid);cout << "线程取消" << tid << endl;void *ret = nullptr;pthread_join(tid, &ret);cout << "主线程正在等待...主线程成功退出,新线程的返回值:" << (long long)ret << endl;
}

注意:这里不推荐使用pthread_cancel调用pthread_self来自己取消自己

六、线程的局部存储

在进程中,两个进程调用同一个变量会发生写时拷贝,但是在线程中却不是这样的

int g_val = 0;void *threadRoutine(void *args)
{while (1){cout << (char *)args << " : " << g_val++ << " &: " << &g_val << endl;sleep(1);}
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while (1){cout << "新线程: " << g_val << "&" << &g_val << endl;sleep(1);}
}

我们的地址是一样的,所以我们的全局变量是被多线程共享的

但是也可以变成私有的,只需要在全局变量前加上__thread就可以了如:

__thread int g_val=0;

我们就可以看到每个线程都有属于自己的全局变量了

  • __thread:修饰全局变量,带来的结果就是让每一个线程各自拥有一个全局变量--线程的局部存储

七、线程调用execl

在进程时调用这个函数只是把内存中和磁盘上的数据替换掉,那么在线程中就是直接将我们所对应的代码和数据全部替换!会影响其他线程,把其他线程终止,然后直接就去调用替换的程序了,就等同于这个进程调用execl进行程序替换

八、分离线程

在进行join时,我们的主线程是必须要的等待的,也可以看到OS并没有给我们更多的选项,可是如果我们不想等待呢?那么我们就可以进行我们的分离线程

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

用法如下

__thread int g_val = 0;void *threadRoutine(void *args)
{pthread_detach(pthread_self());while (1){cout << (char *)args << " : " << g_val++ << " &: " << &g_val << endl;sleep(1);break;}pthread_exit((void *)10);
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while (1){cout << "新线程: " << g_val << "   &" << &g_val << endl;sleep(1);break;}long long n = pthread_join(tid, nullptr);cout << "n:" << n << "错误码" << strerror(n) << endl;
}

如果我们强行join的话,就会产生报错,错误码是非法的参数

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

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

相关文章

腾讯面经学习笔记

&#x1f496; 前言 &#x1f469;‍&#x1f3eb; 参考地址 &#x1f496; 操作系统 1. 进程和线程的区别 本质区别 进程是操作系统资源分配的基本单位线程是任务调度和执行的基本单位 开销方面 每个进程都有独立的代码和数据空间&#xff08;程序上下文&#xff09;&#…

使用大型语言模型进行实体提取

原文地址&#xff1a;Using A Large Language Model For Entity Extraction LLM 能否比传统 NLP 方法更好地提取实体&#xff1f; 2022 年 7 月 12 日 Large Language Models for Generative Information Extraction: A Survey 实体简介 使用Co:here大型语言模型。 实体可以被视…

pytorch_retinaface训练Resnet50_Final.pth过程+无图版安装Nvidia+CUDA驱动GPU

背景 当前处于人脸检测分支&#xff0c;项目就是retinaface官方的代码加上数据集目录结构&#xff0c;目的是训练出最后的模型文件Resnet50_Final.pth 代码 https://gitee.com/congminglst/pytorch_-retinaface.git 项目结构与设计 图片数据集采用widerface&#xff0c; 前…

如何通过隐藏服务器真实IP来防御DDOS攻击

我们知道&#xff0c;服务器对外提供服务&#xff0c;基本上都是放置在公网上的。所以说服务器放置在公网上会面临很多攻击&#xff0c;如果不做好必要的防护措施&#xff0c;服务器被人攻击只是时间上的问题。 而我们面临的众多攻击中&#xff0c;DDoS攻击是最常见同时也是影响…

【Flink】Flink 的八种分区策略(源码解读)

Flink 的八种分区策略&#xff08;源码解读&#xff09; 1.继承关系图1.1 接口&#xff1a;ChannelSelector1.2 抽象类&#xff1a;StreamPartitioner1.3 继承关系图 2.分区策略2.1 GlobalPartitioner2.2 ShufflePartitioner2.3 BroadcastPartitioner2.4 RebalancePartitioner2…

树莓派4B Ubuntu20.04 Python3.9安装ROS踩坑记录

问题描述 在使用sudo apt-get update命令更新时发现无法引入apt-pkg,使用python3 -c "import apt_pkg"发现无法引入&#xff0c;应该是因为&#xff1a;20.04的系统默认python是3.8&#xff0c;但是我换成了3.9所以没有编译文件&#xff0c;于是使用sudo update-alte…

three.js如何实现简易3D机房?(四)点击事件+呼吸灯效果

接上一篇&#xff1a; three.js如何实现简易3D机房&#xff1f;&#xff08;三&#xff09;显示信息弹框/标签&#xff1a;http://t.csdnimg.cn/5W2wA 目录 八、点击事件 1.实现效果 2.获取相交点 3.呼吸灯效果 4.添加点击事件 5.问题解决 八、点击事件 1.实现效果 2.…

蓝桥杯大赛软件python赛道真题:蛇形填数

真题链接&#xff1a;https://www.lanqiao.cn/problems/594/learning/ 题目描述&#xff1a; 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 如下图所示&#xff0c;小明用从1开始的正整数“蛇形”填充无限大的矩阵。 1 2 6 …

【打工日常】使用docker部署个人实时在线文档协助编辑器

一、Etherpad介绍 Etherpad是一个高度可定制的开源在线编辑器&#xff0c;提供真正实时的协作编辑。放在自己的服务器里面&#xff0c;可以更大程度的保护自己工作的隐私&#xff0c;并且Etherpad允许您实时协作编辑文档&#xff0c;就像在浏览器中运行的实时多人编辑器一样这样…

SpringBoot轻松搞定接口防抖(防重复提交)

大家好&#xff0c;我是月夜枫&#xff0c;作为一名合格的码农&#xff0c;在开发后端Java业务系统&#xff0c;包括各种管理后台和小程序等。在这些项目中&#xff0c;我设计过单/多租户体系系统&#xff0c;对接过许多开放平台&#xff0c;也搞过消息中心这类较为复杂的应用&…

基于Java的高校实验室管理系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

【STM32】HAL库 CubeMX 教程 --- 通用定时器 TIM2 定时

实验目标&#xff1a; 通过CUbeMXHAL&#xff0c;配置TIM2&#xff0c;1s中断一次&#xff0c;闪烁LED。 一、常用型号的TIM时钟频率 1. STM32F103系列&#xff1a; 所有 TIM 的时钟频率都是72MHz&#xff1b;F103C8不带基本定时器&#xff0c;F103RC及以上才带基本定时器。…

[BUG] docker运行Java程序时配置代理-Dhttp.proxyHost后启动报错

[BUG] docker运行Java程序时配置代理-Dhttp.proxyHost后启动报错 bug现象描述 版本&#xff1a;2.0.4&#xff08;客户端和服务端都是&#xff09; 环境&#xff1a;私有云环境&#xff0c;只有少量跳板机器可以访问公网&#xff0c;其他机器均通过配置代理方式访问公网 bug现…

9、Linux-安装JDK、Tomcat和MySql

目录 一、安装JDK 1、传输JDK文件&#xff08;.tar.gz&#xff09; 2、解压 3、备份环境变量 4、配置环境变量 5、重新加载环境变量 6、验证&#xff08;java -version&#xff09; 二、安装Tomcat 1、传输文件&#xff0c;解压到/usr/local 2、进入Tomcat的bin目录 …

[PyQt5]PyQt5连接MYSQL时显示Driver not loaded解决方案

在第一次用PyQt5的 QSqlDatabase.addDatabase 连接mysql的时候&#xff0c;可能会出现Driver not loaded的情况&#xff0c;如下&#xff1a; from PyQt5.QtSql import QSqlQuery, QSqlDatabase from PyQt5.QtWidgets import QApplication import sysapp QApplication(sys.ar…

GO语言接入支付宝

GO语言接入支付宝 今天就go语言接入支付宝写一个教程 使用如下库&#xff0c;各种接口较为齐全 "github.com/smartwalle/alipay/v3"先简单介绍下加密&#xff1a; 试想&#xff0c;当用户向支付宝付款时&#xff0c;若不进行任何加密&#xff0c;那么黑客就可以任…

【杂记】IDEA和Eclipse如何查看GC日志

1.Eclipse查看GC日志 1.1 右击代码编辑区 -> Run As -> Run Configurations 1.2 点击Arguments栏 -> VM arguments:区域填写XX参数 -> Run 1.3 控制台输出GC详细日志 2.IDEA查看GC日志 2.1 鼠标右击代码编辑器空白区域&#xff0c;选择Edit 项目名.main()... 2.…

模型驱动软件开发

MDE 模型驱动工程&#xff08;MDE, Model-Driven Engineering&#xff09;是软件工程的一个分支&#xff0c;它将模型与建模拓展到软件开发的所有方面&#xff0c;形成一个多维建模空间&#xff0c;从而将工程活动建立在这些模型的映射和转换之上。[1] MDE的基本原则是将模型视…

实验二(一):IPV4编址及IPV4路由基础实验

一实验介绍 1.关于本实验 IPv4( Internet Protocol Version 4)是 TCP/IP 协议族中最为核心的协议之一。 它工作在 TCP/IP参考模型的网际互联层&#xff0c;该层与 OSI参考模型的网络层相对应。 网络层提供了无连接数据传输服务&#xff0c;即网络在发送分组时不需要先建立连…

学会与自己和解

最近半年来&#xff0c;在学习智能驾驶方面的技术&#xff0c;但有些文档和资料不方便分享&#xff0c;有一段时间没有写 写文档啦&#xff01;那就写一些技术之外的东西吧&#xff0c;最近也一直在学心理建设&#xff0c;学会与自己和解 行动 唯有自己先行动起来&#xff0c;…