线程控制

对线程的控制思路和进程相似,创建、等待、终止,只需要调用接口就行。但是在Linux下没有线程的概念,因为Linux的设计者认为,线程是一种轻量级的进程,毕竟创建线程只需要创建PCB。因此Linux中使用多线程必须使用第三方pthread库,线程库为用户提供接口。


线程的创建——pthread_create

参数:

tread是线程标识符的指针,类似进程pid

attr是线程属性,一般是nullptr

start_routine是线程执行的函数

arg是传递给线程函数的参数

返回值:


线程的终止

线程终止有三种方式:

1.线程函数执行return,就会结束进程

2.线程函数使用pthread_exit接口

3.一个线程中使用pthread_cancel接口终止另一个进程 


线程的等待——pthread_join

 

参数:

 thread是线程标识符

retval是标识符对应线程退出后的返回值,是一个输出型参数。因为线程函数的返回值是void*类型,所以参数类型必须是void**


分离线程——pthread_detach

如果说线程的返回值我们不关心,使用join对操作系统是一种负担,但是不等待线程也会造成内存泄漏。使用这个接口就不用等待线程,在线程执行完自动回收。

分离线程既可以在其他线程分离,也可以自己分离

其他线程传入要分离的线程ID,自己分离调用pthread_self()获取线程tid即可


进程控制的例子:

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;
//使用线程实现从a到b的累加
class Request
{
public:int _start;int _end;string _threadname;Request(int start, int end, string name):_start(start),_end(end),_threadname(name){}
};class Response
{
public:int _val;int _exitcode;Response(int val, int exitcode):_val(val),_exitcode(exitcode){}
};void* cal(void* arg)
{Request* rq = (Request*)arg;Response* rsp = new Response(0, 0);for(int i = rq->_start; i <= rq->_end; i++){usleep(100000);rsp->_val += i;cout << rq->_threadname << " pid:" << getpid() << " operate" <<": ret += " << i << endl;}//线程间共用堆,把主线程的数据释放delete rq;return rsp;
}int main()
{pthread_t tid;Request* rq = new Request(0,50,"mythread");//创建线程cout << "main thread pid:" << getpid() << " create thread" << endl;pthread_create(&tid, nullptr, cal, (void*)rq);void* ret;//等待线程,获取结果pthread_join(tid, &ret);Response* rsp = (Response*)ret;cout << rq->_threadname <<" cal ret = " << rsp->_val << " exitcode = " << rsp->_exitcode << endl; delete rsp;return 0;
}

使用线程库,编译时要用-lpthread选项,声明使用的库
通过指令看到线程的PID相同,因为它们都是同一个进程的执行流资源,LWP是线程标识符,不同线程互不相同


线程ID

我们知道LInux系统没有线程概念,线程这个概念是由线程库来维护的,线程库调用了系统调用接口clone

 clone是创建进程的接口(fork的底层也使用了它),线程库对其封装,提供可以创建线程的接口。那么,线程库必然会对建立的所有线程进行管理,就像操作系统管理进程一样,创建对应的TCB等等。

线程库是一个动态库,进程运行时会加载到共享区。库中就有线程对应的数据结构,这些数据结构都被存储到一个数组中,数组中每个线程的数据结构的地址就是它的tid

从上面的动态库结构看到:线程有自己独立的栈和局部存储


线程栈

独立性

线程栈相互独立,也就是说每个线程即使使用了相同的线程函数,创建的变量也是互不相同的。

#include <iostream>
#include <pthread.h>
#include <vector>#define NUM 4//线程数量
using namespace std;void* fun(void* arg)
{int val = 10;return (void*)&val;//返回栈中变量地址
}int main()
{   vector<pthread_t> tids;//创建多个线程for(int i = 0; i < NUM; i++){pthread_t tid;pthread_create(&tid, nullptr, fun, nullptr);tids.push_back(tid);}//查看栈中变量地址for(auto e : tids){void* ret;pthread_join(e, &ret);cout << (int*)ret << endl;}return 0;
}

可见性

虽然栈是相互独立的,但是并不意味着栈中的数据对其他线程是不可访问的(实际应用中不推荐这种访问)

#include <iostream>
#include <pthread.h>
#include <vector>
#include <unistd.h>
using namespace std;
int* addr;
void* fun(void* arg)
{int val = 0;addr = &val;int cnt = 10;//循环打印valwhile(cnt--){sleep(1);cout << "val:" << val <<endl;}return nullptr;
}
int main()
{//创建线程pthread_t tid;pthread_create(&tid, nullptr, fun, nullptr);//修改valsleep(4);cout << "main change val: 10" << endl;*addr = 10;pthread_join(tid, nullptr);return 0;
}


线程局部存储

一个进程的全局变量对所有的线程都是可见的,如果想要一个线程独有的全局变量,可以使用线程局部存储。

在全局变量定义的前面加上 __thread

#include <iostream>
#include <pthread.h>
#include <vector>
#include <unistd.h>using namespace std;
__thread int gval = 0;void *fun1(void *arg)
{gval += 100;cout << &gval << ' ' << gval << endl;return nullptr;
}void *fun2(void *arg)
{gval += 200;cout << &gval << ' ' << gval << endl;return nullptr;
}
int main()
{vector<pthread_t> tids;pthread_t tid;pthread_create(&tid, nullptr, fun1, nullptr);tids.push_back(tid);pthread_create(&tid, nullptr, fun2, nullptr);tids.push_back(tid);for (auto e : tids){pthread_join(e, nullptr);}return 0;
}

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

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

相关文章

Spring MVC入门2

Postman的使用 接上期我们抛出了一个问题&#xff0c;Postman的使用 可以点击链接下载 https://www.postman.com/downloads/ 安装之后会提示版本升级&#xff0c;直接点击dissmiss即可。 要想发送数据&#xff0c;具体歩奏如下简图&#xff1a; 还有一个更具体的图&#xff…

使用GDAL(C++库)从末尾行开始向上读取图像数据

使用GDAL&#xff08;C库&#xff09;从末尾行读取图像数据 OpenCV等图像库默认的读取方式都是从第一行开始&#xff0c;逐行读取数据&#xff08;自顶向下&#xff09;&#xff0c;填充到内存缓冲区&#xff1b;对于某些特殊应用&#xff0c;需要反行序读取&#xff08;从末尾…

朴素模式匹配算法与KMP算法(非重点)

目录 一. 朴素模式匹配算法1.1 什么是字符串的匹配模式1.2 朴素模式匹配算法1.3 通过数组下标实现朴素模式匹配算法 二. KMP算法2.1 算法分析2.2 用代码实现&#xff08;只会出现在选择题&#xff0c;考察代码的概率不大&#xff09; 三. 手算next数组四. KMP算法的进一步优化4…

在AWS创建一台Windows主机并登录

正文共&#xff1a;1111 字 21 图&#xff0c;预估阅读时间&#xff1a;1 分钟 因为之前微软云Azure免费&#xff0c;我们还做了简单的测试&#xff08;白嫖党618福利&#xff01;来Azure领200美刀&#xff01;外加云主机免费用一年&#xff01;&#xff09;&#xff1b;并且通…

k8s核心操作_存储抽象_K8S中使用Secret功能来存储密码_使用免密拉取镜像_k8s核心实战总结---分布式云原生部署架构搭建033

注意在看的时候一定要把 dxxxx中的xxxx换成--o----c----k----e----r 然后我们再来看一个k8s中的secret的功能,这个功能 用来存储密码的,configMap是用来存配置的 比如我们有个pod,他的镜像,如果是需要密码的,那么 我们现在是从公共仓库拉取的,如果我们从私有仓库拉取,有密码…

从 Icelake 到 Iceberg Rust

本文作者丁皓是Databend 研发工程师&#xff0c;也是 ASF Member&#xff0c; Apache OpenDAL PMC Chair &#xff0c;主要研究领域包括存储、自动化与开源。 太长不看 Icelake 已经停止更新&#xff0c;请改用 iceberg-rust。 Iceberg-rust 是一个由社区驱动的项目&#xff0…

《0基础》学习Python——第十六讲

《文件读写》 一、什么是文件读写 文件读写是指在Python程序中对文件进行读取和写入操作。通过文件读写&#xff0c;可以读取文件中的数据&#xff0c;或者向文件中写入数据。 Python提供了多种文件读写的方式&#xff0c;其中最常用的方式是使用open()函数打开一个文件&#…

深入理解Android中的缓存与文件存储目录

&#x1f31f; 引言 在Android应用开发中&#xff0c;合理管理应用的数据存储至关重要。应用可能需要保存各种类型的数据&#xff0c;从简单的配置信息到多媒体文件&#xff0c;甚至是缓存数据以提高性能和用户体验。Android提供了多个内置目录来满足这些需求&#xff0c;但它…

kubernetes集群环境搭建(二)

kubernetes集群类型 kubernetes集群大体上分为两类&#xff1a;一主多从和多主多从 一主多从&#xff1a;一台Master节点和多台Node节点&#xff0c;搭建简单&#xff0c;但有单机故障风险&#xff0c;适合于测试环境部署多主多从&#xff1a;多台Matser节点和多台Node节点&…

策略模式原理与C++实现

定义 定义一些列算法&#xff0c;把他们一个个封装起来&#xff0c;并且使他们可以相互替换&#xff08;变化&#xff09;。该模式使得算法可独立于使用它的客户程序&#xff08;稳定&#xff09;而变化&#xff08;扩展、子类化&#xff09;。 C实现 在不考虑策略模式的情况…

js基础-小数计算,并转换成带两位的百分比

小数计算&#xff0c;并转换成带两位的百分比 1、需求说明2、执行过程2.1 计算 s12.2 计算 s2 1、需求说明 在工作中&#xff0c;有时需要将计算的小数转换成百分比小数&#xff0c;但是在js代码中&#xff0c;计算公式一点点的区别就会影响到最终的结果&#xff0c;如下面代码…

vue视频、图片自动轮播并伴随进度条

废话不多说直接上代 多余没用的部分自己看着删除 <template><div class"showImg"><el-carousel ref"carousel" trigger"hover" :autoplay"false" class"dimControl" :height"${(currenInnerWith*0.37…

spring框架之AOP注解方式(java代码实例)

目录 半注解形式&#xff1a; 业务层接口实现类&#xff1a; 编写切面类&#xff1a; 在配置文件里面唯一需要加的&#xff1a; 测试类&#xff1a; 全注解形式&#xff1a; 不要配置文件&#xff0c;改为配置类&#xff1a; 同样的业务层接口实现类&#xff1a; 同样的…

2024年【天津市安全员C证】免费试题及天津市安全员C证考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证免费试题根据新天津市安全员C证考试大纲要求&#xff0c;安全生产模拟考试一点通将天津市安全员C证模拟考试试题进行汇编&#xff0c;组成一套天津市安全员C证全真模拟考试试题&#xff0c;学员可通过…

Java红娘婚恋相亲交友系统小程序源码

红娘婚恋相亲交友小程序&#xff1a;遇见爱情&#xff0c;从指尖开始&#x1f496; &#x1f4f1; 掌中红娘&#xff0c;随时待命 &#x1f48c; 在这个数字化时代&#xff0c;爱情也迎来了它的新舞台——“红娘婚恋相亲交友小程序”。只需轻轻一点&#xff0c;你的专属红娘就…

QT--控件篇四

一、对话框 在软件开发中&#xff0c;对话框&#xff08;Dialog&#xff09;是一种常见的用户界面元素&#xff0c;用于与用户进行交互和获取信息。它通常以模态或非模态的形式出现&#xff0c;模态对话框会阻止用户与应用程序的其他部分交互&#xff0c;直到对话框关闭为止&a…

硕博电子智能控制器、触摸显示屏在集装箱跨运车上的应用

港口跨运车&#xff0c;又称跨运车或轮胎式龙门吊(RTG)&#xff0c;专门用于集装箱码头的装卸和搬运作业&#xff0c;能够迅速完成集装箱在码头前沿、堆场区域以及仓库之间的运输和堆垛&#xff0c;大幅度缩短了装卸周期&#xff0c;提高了港口物流周转效率。 现代跨运车往往配…

C++笔试强训4

文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 %o就是输出八进制的无符号数&#xff0c;0123&#xff0c;&#xff0c;以0开头&#xff0c;本来就是八进制&#xff0c;所以输出为123&#xff0c;123是十进制&#xff0c;转化为八进制就是173. 故选…

【Python基础教程】制作一个宿舍管理系统,数据库宿舍管理系统代码!(完整版,附源码)

今天我们一起学习一个新的小案例——宿舍管理系统。主要涉及列表、字典的初始化、增加、删除、修改和查询操作&#xff0c;以及函数的定义和调用。 一、需求&#xff1a; 有操作指引界面&#xff0c;显示操作号 能添加一个新的入住学生信息&#xff0c;包括学生姓名、宿舍号床…

如何让员工在培训后持续应用六西格玛工具?

要让员工在培训后持续应用六西格玛工具&#xff0c;首先需要明确六西格玛的核心价值及其在企业中的应用意义。六西格玛是一种数据驱动的管理方法论&#xff0c;旨在通过减少变异和浪费&#xff0c;提高流程效率和质量&#xff0c;进而提升企业的竞争力。然而&#xff0c;仅仅通…