当前位置: 首页 > news >正文

【Linux】线程函数和线程同步详细整理(金针菇般细)

目录

一,线程函数

1.获取当前线程ID

2.创建线程

3.退出线程

4.阻塞线程

5.分离线程

6.取消线程

7.线程比较

8.测试代码(线程函数总结)

二,线程同步

1.互斥锁

2.读写锁

3.条件变量

4.信号量


一,线程函数

  • 参考文章: 线程 | 爱编程的大丙

man command                //Linux终端命令

# 查阅 command 命令的使用手册,包含了绝大部分的命令和函数的详细使用说明

获取当前线程IDpthread_t pthread_self(void);
创建线程int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *),void *arg);
退出线程void pthread_exit(void *retval);
阻塞线程int pthread_join(pthread_t thread, void **retval);
分离线程int pthread_detach(pthread_t thread);
取消线程(杀死线程)int pthread_cancel(pthread_t thread);
线程比较int pthread_equal(pthread_t t1, pthread_t t2);

1.获取当前线程ID

//获取当前线程的线程ID,ID类型为pthread_t,它是一个无符号长整型数
pthread_t pthread_self(void);
  • 返回值: 永远返回成功,返回被调用者的线程ID

2.创建线程

//在进程中调用线程创建函数来创建一个子线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *),void *arg);
参数介绍
thread输出参数,线程创建成功会将线程ID写入到该指针所指向的内存中
attr线程的属性,一般设置为NULL,即线程的创建使用默认属性
start_routine函数指针,子线程的业务处理函数,即传入的函数指针会在该子线程中执行
arg函数参数,和start_routine指针指向的函数参数匹对,即该参数是传递给start_routine指针所指向的函数
  • 返回值:创建成功返回0,创建失败返回一个错误号并且*thread值未定义

3.退出线程

//线程退出不会影响到其它线程的正常运行,子线程或主线程都可以调用
void pthread_exit(void *retval);
  • 参数:被调用线程退出时,其它线程可通过retval获取线程退出时携带的数据。不需要数据可以指定为NULL

4.阻塞线程

//函数被调用一次,只会回收一个子线程,如果有多个线程需要循环传入线程ID进行回收
int pthread_join(pthread_t thread, void **retval);
  • 参数介绍
    • thread:要被阻塞的线程ID,指定的线程必须是可被阻塞的
    • retval:所指向一级指针的地址是一个输出参数,该地址中存储了pthread_exit()传出的数据,不需要数据可以指定为NULL
  • 返回值:成功返回0,失败返回一个错误码

5.分离线程

/*
1.传入分离子线程的线程ID,便会与主线程分离,当子线程退出的时候,其占用的资源就会被系统的其它进程接管并回收。
2.不可对同一线程重复分离,不然会出现未定义行为
*/
int pthread_detach(pthread_t thread);

6.取消线程

int pthread_cancel(pthread_t thread);

7.线程比较

int pthread_equal(pthread_t t1, pthread_t t2);

8.测试代码(线程函数总结)

#include <cstdio>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>//子线程处理代码
void* threadFun(void *_arg){printf("子线程线程ID:%ld 传入参数值:%ld\n", pthread_self(),*(int*)_arg);for (int i = 0; i < 5; i++){sleep(1);printf("subThread-i: = %d\n", i);if (i == 3) {int* val = (int*)malloc(sizeof(int));*val = i;pthread_exit(val);  //子线程退出携带的数据val可以被主线程中调用pthread_join获取}}return nullptr;
}int main()
{printf("主线程线程ID:%ld\n", pthread_self());for (int i = 0; i < 5; i++){sleep(1);printf("main-i: = %d\n", i);}pthread_t tid;  //创建一个子线程int thread_arg = 1008;   //传给threadFun()线程工作函数的参数int flag = pthread_create(&tid, nullptr, threadFun, (void*)&thread_arg);if (flag == 0){printf("子线程创建成功,线程ID:%ld  传入threadFun()线程函数的参数值:%d\n", tid,thread_arg);}//pthread_detach(tid);    /** 线程分离之后在主线程使用pthread_join()就会报段错误(核心已转储)* ,因为子线程退出时,其占用的内核资源被系统其它进程回收了,然而你又对它进行操作。*/void *subTd_retval = nullptr;pthread_join(tid, &subTd_retval);   //阻塞子线程,并获取子线程退出时的数据printf("子线程 %ld 返回的数据:%ld\n", tid, *(int*)subTd_retval);pthread_detach(tid);    //这里让子线程与主线程分离pthread_exit(nullptr);  //让主线程自己退出return 0;
}

二,线程同步

 参考文章: 线程同步 | 爱编程的大丙

1.当多个线程对共享资源(多个线程共同访问的变量)进行访问的时候就会出现数据混乱的问题,所以就需要进行线程同步,所谓的线程同步实际上是各线程按先后顺序依次对共享资源进行访问,而不是同时进行的,其实也就是让各线程去抢占CPU时间片,抢到就访问数据,没抢到就挂起,这之间会涉及到上下文的切换。虽然降低了运行效率,但提高了数据访问的安全性,这是值得的。

2.线程同步有四种方式:互斥锁,读写时,条件变量,信号量。

3.互斥锁,读写时,条件变量在头文件pthread中,信号量在头文件semaphore中。

1.互斥锁

//每一个共享资源对应一把锁,锁的个数和线程的个数无关
pthread_mutex_t mutex;//初始化互斥锁,被restrict修饰的指针可以访问指向的内存地址
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//释放互斥锁资源
int pthread_mutex_destroy(pthread_mutex_t *mutex);//修改互斥锁状态,对传入的互斥锁进行加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//对传入的互斥锁进行尝试加锁,
int pthread_mutex_trylock(pthread_mutex_t *mutex);//对传入的互斥锁进行解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);

2.读写锁

//读写锁是互斥锁的升级版,读锁是共享的,写锁是互斥(独占)的。写锁优先级比读锁高
pthread_rwlock_t rwlock;//初始化读写锁,attr默认为NULL就行
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);//释放读写锁占用的系统资源
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//修改读写锁状态,锁定读操作,读锁可以重复锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//对传入的读写锁进行尝试加读锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//对传入的读写锁进行加写锁
int pthread_rwlock_wdlock(pthread_rwlock_t *rwlock);//对传入的读写锁进行尝试加写锁
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

3.条件变量

  • 条件变量不是处理线程同步的,而是进行线程的阻塞。多线程实现线程同步需要配合互斥锁来使用。
//条件变量类型的定义
pthread_cond_t cond;//初始化条件变量,一般attr默认为NULL就行
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_cond_t *restrict attr);//释放条件变量资源
int pthread_cond_destroy(pthread_cond_t *cond);//线程阻塞函数,哪个线程调用这个函数就会阻塞哪个线程
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);//唤醒在条件变量上阻塞的线程(至少一个)
int pthread_cond_signal(pthread_cond_t *cond);//唤醒在条件变量阻塞的全部线程
int pthread_cond_broadcast(pthread_cond_t *cond);

4.信号量

  •  信号量 主要是阻塞线程,不能保证线程安全,如果要保证线程安全,需要信号量和互斥锁一起使用

1.定义信号量变量

sem_t sem;

2.初始化信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
  • 参数
    • sem:信号量变量地址
    • pshared:0-线程同步,!0-进程同步
    • value:初始化信号量*sem拥有的资源数(>=0),为0就会阻塞线程

3.销毁信号量

int sem_destroy(sem_t *sem);

4.锁住一个信号量资源,资源数=0时会阻塞线程

int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

5.释放一个信号量资源

int sem_post(sem_t *sem);

6.获取信号量的资源数

//sval是输出参数,可以通过sval获取信号量sem中拥有的资源数量
int sem_getvalue(sem_t *sem, int *sval);

相关文章:

【Linux】线程函数和线程同步详细整理(金针菇般细)

目录 一&#xff0c;线程函数 1.获取当前线程ID 2.创建线程 3.退出线程 4.阻塞线程 5.分离线程 6.取消线程 7.线程比较 8.测试代码&#xff08;线程函数总结&#xff09; 二&#xff0c;线程同步 1.互斥锁 2.读写锁 3.条件变量 4.信号量 一&#xff0c;线程函数 …...

Python学习笔记6:抽象

抽象 函数 判断某个对象是否可调用&#xff0c;可使用内置函数callable >>> import math >>> x 1 >>> y math.sqrt >>> callable(x) False >>> callable(y) True斐波那契数组 def fibs(num): result [0, 1] for i i…...

自己手写一个redux

提起 Redux 我们想到最多的应该就是 React-redux 这个库&#xff0c;可是实际上 Redux 和 React-redux 并不是同一个东西, Redux 是一种架构模式&#xff0c;源于 Flux。 React-redux 是 Redux 思想与 React 结合的一种具体实现。 在我们使用 React 的时候&#xff0c;常常会遇…...

mysql调优参数

my.conf [client] port 端口 socket sokcet位置 [mysqld] basedir mysql位置 port 3306 socket sokcet位置 datadir data目录 pid_file mysqld.pid位置 bind_address 0.0.0.0 lower_case…...

JavaEE简单示例——再插入的同时获取插入的主键列

简单介绍&#xff1a; 在某些时候&#xff0c;我们在插入完成一条语句之后&#xff0c;我们会想要返回之前插入的这条语句的主键列的数据&#xff0c;进行下一步的展示或者修改&#xff0c;我们就可以使用MyBatis的主键回写功能&#xff0c;帮助我们获取插入成功的一条数据的主…...

sql语句练习

一、现有以下两张表&#xff1a;第一张表名为cust&#xff0c;其表结构如下&#xff1a;第二张表名为mark&#xff0c;其表结构如下:1) [5分]请写出计算 所有学生的英语平均成绩的sq|语句。2) [5分]现有五 个学生,其学号假定分别为11,22,33,44,55;请用一条SQL语句实现列出这五个…...

广州蓝景—结合chatGPT下的教育模式变化

最近爆火的人工智能AI聊天工具ChatGPT&#xff0c;不仅在互联网&#xff0c;更是在各行各业中&#xff0c;得到了广泛的传播&#xff0c;应该没有哪一个不知道它的存在&#xff0c;但其实你又是否知道&#xff0c;其实ChatGPT是一类模型的统称&#xff0c;随着人工智能的快速发…...

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——shuffle机制

3.3.1Shuffle机制 Map方法之后&#xff0c;Reduce方法之前的数据处理过程称之为Shuffle。 3.3.2Partition分区 1、问题引出 要求将统计结果按照条件输出到不同文件中&#xff08;分区&#xff09;。比如&#xff1a;将统计结果按照手机归属地不同省份输出到不同文件中&#…...

4|无线传感器网络与应用|无线传感器网络原理及方法-许毅版|第3章:无线传感器网络通信-3.1协议结构 3.2物理层|青岛科技大学|课堂笔记

第3章&#xff1a;无线传感器网络通信3.1协议结构3.1.1 OSI参考模型1.网络通信协议MAC层和物理层采用IEEE 802.15.4协议*(1)物理层wsn物理层负责信号的调制和数据的收发&#xff0c;传输介质&#xff1a;无线电、红外线、光波等。(2)数据链路层wsn数据链路层负责数据成帧、帧检…...

关机时,如何控制systemd服务的关闭顺序

关机时&#xff0c;如何控制systemd服务的关闭顺序? 在工作中&#xff0c;我们通常遇到的问题是&#xff0c;如何控制systemd服务的启动顺序&#xff0c;同志们第一反应就会是使用Before或者After去进行控制。 问题来了&#xff0c;如果服务启动时没有顺序要求&#xff0c;但…...

关于MySQL镜像构建过程中添加自动初始化数据库

需求描述一般而言&#xff0c;我们在拉取了 mysql 镜像并运行之后&#xff0c;其中的并不会存在我们自定义的数据库&#xff0c;都是在镜像运行后&#xff0c;自己主动导入数据库&#xff0c;那么有没有方式可以一运行 mysql 镜像&#xff0c;对应生成的 mysql 容器中就有我们自…...

CS144-Lab2

实验架构 除了写入传入流之外&#xff0c;TCPReceiver 还负责通知 sender 两件事&#xff1a; “First unassembled” 字节的索引&#xff0c;称为“acknowledgment”或 “ackno”。这是接收方需要来自发送方的第一个字节。“first unassembled ” 索引和“first unacceptable…...

Linux内核驱动之efi-rtc

Linux内核驱动之efi-rtc1. UEFI与BIOS概述1.1. BIOS 概述1.1.1. BIOS缺点&#xff1a;1.1.2. BIOS的启动流程1.2 UEFI 概述1.2.1 Boot Sevices&#xff1a;1.2.2. Runtime Service&#xff1a;1.2.3. UEFI优点&#xff1a;1.2.4. UEFI启动过程&#xff1a;1.3 Legacy和UEFI1.4 …...

Java 字符串

文章目录一、API二、String1. String 构造方法2. String 对象的特点3. 字符串的比较4. 用户登录案例5. 遍历字符串6. 统计字符次数7. 拼接字符串8. 字符串反转三、StringBuilder1. 构造方法2. 添加及反转方法3. 与 String 相互转换4. 拼接字符串升级版5. 字符串反转升级版一、A…...

麦克风阵列波束基本概念理解

波束形成 本质上是设计合适的滤波器&#xff0c;对于一类固定滤波器系数的阵列来说&#xff0c;无论输入信号或者噪声信号的统计特征如何&#xff0c;其滤波器系数固定不变&#xff0c;此类波束形成叫Fixed Beamforming&#xff0c;固定波束形成好比传统数字信号处理里面的经典…...

JAVA保姆式JDBC数据库免费教程之02-连接池技术

连接池 连接池概念 ​ 概念&#xff1a;其实就是一个容器(集合)&#xff0c;存放数据库连接的容器。 当系统初始化好后&#xff0c;容器被创建&#xff0c;容器中会申请一些连接对象&#xff0c;当用户来访问数据库时&#xff0c;从容器中获取连接对象&#xff0c;用户访问完…...

视频片段怎么做成gif图?快试试这2种方法

动态gif图片作为当下非常常用的表情包&#xff0c;其丰富的内容生动的画面深受大众喜爱。那么&#xff0c;当我们想要将电影或是电视剧中的某一片段做成gif动态图片的时候&#xff0c;要如何操作呢&#xff1f;接下来&#xff0c;给大家分享两招视频转化gif的小窍门–使用【GIF…...

2.20计算机如何工作

一.计算机组成1.冯诺依曼体系CPU 中央处理器: 进行算术运算和逻辑判断.存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)输入设备: 用户给计算机发号施令的设备.输出设备: 计算机个用户汇报结果的设备内存和外存的区别(面试)访问速度:内存快,外存慢存储空间:内存小,外…...

[golang gin框架] 5.Cookie以及Session

1.Cookie(1).介绍HTTP 是无状态协议,简单地说&#xff0c;当浏览了一个页面&#xff0c;然后转到同一个网站的另一个页面&#xff0c;服务器无法认识到这是同一个浏览器在访问同一个网站,每一次的访问&#xff0c;都是没有任何关系的,如果要实现多个页面之间共享数据的话就可以…...

【牛客刷题专栏】0x0B:JZ3 数组中重复的数字(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录前言问题…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...

Python学习(8) ----- Python的类与对象

Python 中的类&#xff08;Class&#xff09;与对象&#xff08;Object&#xff09;是面向对象编程&#xff08;OOP&#xff09;的核心。我们可以通过“类是模板&#xff0c;对象是实例”来理解它们的关系。 &#x1f9f1; 一句话理解&#xff1a; 类就像“图纸”&#xff0c;对…...