Linux下的 c 多线程与线程同步(二)
关于线程本人力推苏丙榅老师(曾经担任黑马讲师)的视频讲解,B站与老师自己博客都有老师的讲解,内容通俗易懂非常适合学习,本人线程学习皆从老师处学习。
https://subingwen.cn/linux/thread-sync/
上一章节讲述了线程的创建与使用,本章节主要讲述线程同步;
为什么要线程同步?
举个栗子,相信年轻一的的小伙伴都有想过,假如我银行卡内有300块,我提到支付宝的时候同一时间在ATM里取300,那是不是就能赚他300? 很遗憾,银行可不会给你钻空子,此时就引出了线程同步的概念
线程同步的概念:
很多小伙伴认为线程同步是执行的同步,实则不然;所谓线程同步,其实是多线程情况下对于内存中的共享资源进行访问修改的时候,使这个共享资源按顺序被修改,所谓的同步并不是多个线程同时对内存进行访问,而是按照先后顺序依次进行的。
其实使用原子变量也可以达到以上效果,而且不用开锁解锁,更加节省资源,有兴趣的小伙伴可以去了解一下,这里不过多赘述
1.1 同步方式
对于多个线程访问共享资源出现数据混乱的问题,需要进行线程同步。常用的线程同步方式有四种:互斥锁、读写锁、条件变量、信号量。所谓的共享资源就是多个线程共同访问的变量,这些变量通常为全局数据区变量或者堆区变量,这些变量对应的共享资源也被称之为临界资源。
1.2互斥锁
创建的锁对象中保存了当前这把锁的状态信息:锁定还是打开,如果是锁定状态还记录了给这把锁加锁的线程信息(线程 ID)。一个互斥锁变量只能被一个线程锁定,被锁定之后其他线程再对互斥锁变量加锁就会被阻塞,直到这把互斥锁被解锁,被阻塞的线程才能被解除阻塞。一般情况下,每一个共享资源对应一个把互斥锁,锁的个数和线程的个数无关。
// 初始化互斥锁
// restrict: 是一个关键字, 用来修饰指针, 只有这个关键字修饰的指针可以访问指向的内存地址, 其他指针是不行的
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
// 释放互斥锁资源
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
mutex: 互斥锁变量的地址
attr: 互斥锁的属性,一般使用默认属性即可,这个参数指定为 NULL
加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//给代码段加锁
线程会判断当前锁的状态:
如果是上锁状态:线程会阻塞在此处
如果为未锁:线程加锁并记录锁状态,向下执行
尝试加锁
// 尝试加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
线程会判断当前锁的状态:
如果是上锁状态:线程不会被阻塞,加锁失败直接返回错误号
如果为未锁:线程加锁并记录锁状态,向下执行
解锁
// 对互斥锁解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
1.3读写锁
读写锁相当于高级的互斥锁,就像svip与vip一样。
创建:
pthread_rwlock_t rwlock;
之所以称其为读写锁,是因为这把锁既可以锁定读操作,也可以锁定写操作。为了方便理解,可以大致认为在这把锁中记录了这些信息:
1.1 锁的状态:锁定 / 打开
1.2 锁定的是什么操作:读操作 / 写操作,使用读写锁锁定了读操作,需要先解锁才能去锁定写操 作,反之亦然。
1.3 哪个线程将这把锁锁上了
特点:1.使用读写锁的读锁锁定了临界区,线程对临界区的访问是并行的,读锁是共享的。
2.使用读写锁的写锁锁定了临界区,线程对临界区的访问是串行的,写锁是独占的。
3.使用读写锁分别对两个临界区加了读锁和写锁,两个线程要同时访问者两个临界区,访问写锁临界区的线程继续运行,访问读锁临界区的线程阻塞,因为写锁比读锁的优先级高。
加读锁:
// 在程序中对读写锁加读锁, 锁定的是读操作
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
加写锁:
// 在程序中对读写锁加写锁, 锁定的是写操作
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
解锁:
// 解锁, 不管锁定了读还是写都可用解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
1.4条件变量
一般情况下条件变量主要针对消费者模型,并且和互斥锁配合使用
- 严格意义上来说,条件变量的主要作用不是处理线程同步,而是进行线程的阻塞。如果在多线程程序中只使用条件变量无法实现线程的同步,必须要配合互斥锁来使用。
- 条件变量只有在满足指定条件下才会阻塞线程,如果条件不满足,多个线程可以同时进入临界区,同时读写临界资源,这种情况下还是会出现共享资源中数据的混乱。
pthread_cond_t cond;//创建条件变量
// 初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
// 销毁释放资源
int pthread_cond_destroy(pthread_cond_t *cond);
参数
- cond为对象地址
- attr一般情况下置空,使用默认属性
同步
// 线程阻塞函数, 哪个线程调用这个函数, 哪个线程就会被阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
若条件变量在此处阻塞,会自动打开传入的互斥锁,以便其他的线程正常运行,理论上来说可以使全部的消费者线程阻塞在此处,当生产者线程抢到cpu时间片后正常加锁执行后调用解除阻塞函数;使消费者线程正常执行,此时阻塞在此处的消费者线程会抢夺此处的互斥锁,如何正常执行,如果没抢到锁,则继续阻塞;
解除阻塞:
// 唤醒阻塞在条件变量上的线程, 至少有一个被解除阻塞
int pthread_cond_signal(pthread_cond_t *cond);
// 唤醒阻塞在条件变量上的线程, 被阻塞的线程全部解除阻塞
int pthread_cond_broadcast(pthread_cond_t *cond);
此文章为作者学习时的记录,如有缺陷多多包涵
Linux下的 c 多线程与线程同步(二)相关推荐
- linux使用线程实现生产者消费者问题,Linux下生产者与消费者的线程实现
代码见<现代操作系统> 第3版. 为了显示效果,添加了printf()函数来显示运行效果 #include #include #define MAX 20 pthread_mutex_t ...
- 3、Linux多线程,线程同步(转)
3.Linux多线程,线程同步 5)线程私有数据 进程内的所有线程共享进程的数据空间,因此全局变量为所有线程所共有.但有时线程也需要保存自己的私有数据,这时可以创建线程私有数据(Thread-spec ...
- linux下最简单多线程单文件socks5代理proxy服务器程序(仅一个c文件,带详细注解)
2020.9.11 网上看的都比较复杂,GITHUB找了一个多线程的相对简单的MicroSocks项目,花了几周时间(没办法,菜鸟一个)改了一下,改成单文件,测试OK. /* wxl_socks5_p ...
- VC++ MFC 多线程及线程同步(详细、全面总结!)
更多详情:http://blog.csdn.net/whyacinth/ VC++ MFC 多线程及线程同步 关键词: MFC 多线程及线程同步 ...
- Java多线程之线程同步机制(锁,线程池等等)
Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...
- Linux下Rsync+Inotify-tools实现数据实时同步
说明: 操作系统:CentOS 5.X 源服务器:192.168.21.129 目标服务器:192.168.21.127,192.168.21.128 目的:把源服务器上/home/www.osyun ...
- Linux下的主辅DNS服务器同步
Linux下的主辅DNS服务器同步 一.系统环境介绍 二.辅助DNS搭建 1.安装yum包 2.设置服务自启 3.编辑dns主配置文件 4.编辑区域文件 5.配置正向文件 6.配置反向文件 7.重启服 ...
- Linux系统编程(九)线程同步
Linux系统编程(九)线程同步 一.什么是线程同步? 二.互斥量 三.条件变量 pthread_cond_wait函数 pthread_cond_signal函数 生产者和消费者模型 一.什么是线程 ...
- C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent
C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent 本章概要: 1:终止状态和非终止状态 2:AutoResetEvent和ManualResetE ...
最新文章
- 爱送礼成中国好前任,谢谢你让我认识了快递员
- js 排列 组合 的一个简单例子
- npm更改为淘宝镜像
- WinCE 开始菜单StartMenu_Create()函数代码分析
- mysql建表时主键_mysql建表时怎么设置主键?
- 基于安全压缩感知的大数据隐私保护
- mysql 傻瓜式管理_傻瓜式教学【数据库管理工具Navicat】
- 视频抽帧并存图 python_使用Python实现跳帧截取视频帧
- 限时下载 | 132G编程资料:Python、JAVA、C,C++、机器人编程、PLC,入门到精通~
- python open函数关于w+ r+ 读写操作的理解
- Android虚拟电脑,如何让你的android模拟器连接上你电脑的网络
- mikrotikROS路由配置L2TP
- I Sold Out for the Cash - 2022/8/10
- Linux学习-账户管理
- 免费获取对方ip地址PHP源码
- 铁威马F2-NAS2评测(家用云存储NAS)
- 【Python魔术方法】py复习
- java搭建直播平台
- mt4的服务器在哪个文件,mt4的服务器地址
- Parsec测试基准程序在zynq板上测试