3. 线程的同步与互斥

为什么需要同步与互斥

​ 一个进程运行时,数据存储在内存中。如果一个数据要进行运算,必须先将数据拷贝到寄存器中。比如要对栈上的一个int i进行“++”操作,需要将i的值拷贝到寄存器中,将该值自加后再拷贝到原来的内存。

​ 如果此时有两个线程均进行的是这样的操作,可能出现两个线程都拷贝了i原来的值到寄存器,然后各种加一,再拷贝到i对应内存的情况,最终导致i这个变量只自加了一次。

(个人理解:写数据的过程为:

  1. 把内存中的i拷贝进寄存器;
  2. i++;
  3. 读取寄存器中的i到内存;

两个线程同时写产生的问题:

  1. A线程把i拷贝进寄存器,i++;
  2. 此时B线程又把内存中的i拷贝进了寄存器,覆写了原本寄存器中已经+1的i,B线程执行i++操作;
  3. A、B线程分别读取寄存器中的i;

此时的i就只自加了一次。

线程的同步与互斥的三种机制

  • 互斥量
  • 信号量
  • 条件变量

3.1 互斥量

(1)原子性

​ 如果一个线程锁定了一个互斥量,那么临界区内的操作要么全部完成,要么一个也不执行。

(2)唯一性

​ 需要注意的问题:有可能上锁后忘记解锁;或者在解锁语句前程序抛出异常,导致无法解锁。

​ 在c++中,lock()之后容易忘记unlock(),与忘记释放指针所指堆内存空间导致内存泄露的情况类似。于是与智能指针类似,也有了lock_guard,用来防止开发人员忘了解锁。

lock_guard:

(3)非繁忙等待

3.2 互斥量使用

互斥量使用过程如下

(1)互斥量声明与初始化

(2)互斥量加锁

​ C语言中,通过系统调用pthread_mutex_lock对互斥量加锁。

(3)互斥量判断是否加锁

​ pthread_mutex_trylock()用于判断线程是否加锁,语义与pthread_mutex_lock类似,不同的是在锁被占用时返回EBUSY错误而不是挂起等待。

(4)访问共享资源

(5)互斥量解锁

​ pthread_mutex_unlock调用对指定的互斥量解锁。

(6)互斥量销毁

​ pthread_mutex_destroy()用于注销一个互斥量。

3.3 信号量

​ 信号量可以实现线程的同步与互斥(设置不同的初始值,例如同步设为0,互斥设为1),其本质就是P/V操作,

也就是wait(S)和signal(S)这两个原语。

1. 记录型信号量

value:代表资源数目的整型变量;

L:进程链表,用于链接所有等待该资源的进程。

记录型信号量可描述为:

typedef struct{
int value;
struct process *L;
}semaphore;

相应的wait(S)和signal(S)操作如下:

void wait(semaphore S)	//相当于申请资源
{
S.value--;
if(S.value < 0)
{
add this process to S.L;
block(S.L); //block原语,进行自我阻塞,放弃处理机
}
}
void signal(semaphore S)	//相当于释放资源
{
S.value++; //释放一个进程,使可供分配的资源数+1
if(S.value <= 0) //若+1后仍是S.value <= 0,则表示在S.L中仍有等待该资源的进程被阻塞
{
remove a process P from S.L;
wakeup(P); //wakeup原语,唤醒S.L中的第一个等待进程
}
}

2. 利用信号量实现同步

设S为进程P1,P2的公共信号量,初值为0

进程P2中的y语句要使用P1中x语句的运行结果,所以只有当x执行完毕后y才可以执行。

实现进程同步的算法如下:

semaphore S = 0;	//初始化信号量
P1()
{
x; //语句x
V(S); //告诉进程P2,语句x已经完成
...
}
P2()
{
...
P(S); //检查语句x是否执行完成
y; //检查无误,运行y语句
...
}

3. 利用信号量实现进程互斥

设S为进程P1,P2的公共信号量,初值为1

实现进程互斥的算法如下:

semaphore S = 1;	//初始化信号量
P1()
{
...
P(S); //准备开始访问临界区,加锁
进程P1的临界区;
V(S); //访问结束,解锁
...
}
P2()
{
...
P(S); //准备开始访问临界区,加锁
进程P2的临界区;
V(S); //访问结束,解锁
...
}

3.4 信号量的使用方法

(1)信号量初始化

(2)信号量的P操作

​ 如果信号量的value值为0,则阻塞当前线程;若不为0,则将value减1。

(3)信号量的V操作

(4)信号量的销毁

(5)信号量的其它调用

Linux多线程(8.3 线程同步与互斥)的更多相关文章

  1. .NET面试题解析(07)-多线程编程与线程同步

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等, ...

  2. .NET面试题解析(07)-多线程编程与线程同步 (转)

    http://www.cnblogs.com/anding/p/5301754.html 系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实 ...

  3. 线程同步 - POSIX互斥锁

    线程同步 - POSIX互斥锁 概括 本文讲解POSIX中互斥量的基本用法,从而能达到简单的线程同步.互斥量是一种特殊的变量,它有两种状态:锁定以及解锁.如果互斥量是锁定的,就有一个特定的线程持有或者 ...

  4. java核心知识点学习----多线程并发之线程同步

    1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...

  5. linux线程同步(1)-互斥量

    一.概述                                                   互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行 ...

  6. Android多线程研究(3)——线程同步和互斥及死锁

    为什么会有线程同步的概念呢?为什么要同步?什么是线程同步?先看一段代码: package com.maso.test; public class ThreadTest2 implements Runn ...

  7. 细说C#多线程那些事 - 线程同步和多线程优先级

    上个文章分享了一些多线程的一些基础的知识,今天我们继续学习. 一.Task类 上次我们说了线程池,线程池的QueueUserWorkItem()方法发起一次异步的线程执行很简单 但是该方法最大的问题是 ...

  8. Win32多线程编程(3) — 线程同步与通信

      一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...

  9. UNIX环境高级编程——线程同步之互斥锁、读写锁和条件变量(小结)

    一.使用互斥锁 1.初始化互斥量 pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥量 int pthread_mutex_init( ...

  10. Linux多线程实践(1) --线程理论

    线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 一切进程至少有一个执行线程; 进程  VS. 线程  ...

随机推荐

  1. Dijkstra(迪杰斯特拉)算法C++实现&讲解

    Dijkstra迪杰斯特拉算法及C++实现 Dijkstra算法是典型的最短路径路由算法,用来计算一个节点到其他所有节点的最短路径.算法的基本思想和流程是:1. 初始化出发点到其它各点的距离dist[ ...

  2. 开源不到 48 小时获 35k star 的推荐算法「GitHub 热点速览」

    本周的热点除了 GPT 各类衍生品之外,还多了一个被马斯克预告过.在愚人节开源出来的推特推荐算法,开源不到 2 天就有了 35k+ 的 star,有意思的是,除了推荐算法本身之外,阅读源码的工程师们甚 ...

  3. [MyBatis]问题:ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

    错误信息 ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging onl ...

  4. Android 为什么事件分发的入口函数是dispatchTouchEvent

    参考:https://xiaozhuanlan.com/topic/8946537021 从触摸屏幕到事件在底层传输最终会到: private int processPointerEvent(Queu ...

  5. 我的OpenAI库发布了!!!

    chatGPT正式发布已经有段时间了,这段时间我也深度体验了chatGPT的魅力. OpenAI除了提供网页版的chatGPT,还通过api的形式提供了很多其它服务,包括文字纠错.图片生成.音频转换等 ...

  6. Java全栈开发/API

    2023/4/16 记录我学习的网站 前端 vuejs axios异步请求 微信开发者文档 uniapp开发文档 快速参考备忘清单 免费前端接口 读取json vant4UI cubeUI mintU ...

  7. 如何生成文本: 通过 Transformers 用不同的解码方法生成文本

    简介 近年来,随着以 OpenAI GPT2 模型 为代表的基于数百万网页数据训练的大型 Transformer 语言模型的兴起,开放域语言生成领域吸引了越来越多的关注.开放域中的条件语言生成效果令人 ...

  8. C++ Primer 5th 阅读笔记:前言

    机器效率和编程效率 Its focus, and that of its programming community, has widened from looking mostly at machi ...

  9. (亲自实践)python OpenCV已经安装但是import cv2的方法不能用

    最近在学习验证码图片识别,安装完pip install opencv-python之后,发现导入的方法命令有底纹,也就是不能使用 解决方案如下: 找到安装python的路径,安装完opencv-pyt ...

  10. Python定时任务框架apscheduler的简单使用

    apscheduler的简单使用 APScheduler有四大组件: 1.触发器 triggers : 触发器包含调度逻辑.每个作业都有自己的触发器,用于确定下一个任务何时运行.除了初始配置之外,触发 ...