第一次使用博客,把自己学习的心得记录下来,与大家分享,有什么不足请指正,共同学习!
本文记录的是线程同步的一个经典问题,读写问题。这个场景在实际的应用中很常见,多线程中同时对文件进行读写很容易出问题,在此啰嗦一下,主要问题无外乎以下几种:
1.**丢失修改**。当A对文件进行修改后还没来得及更新,这时候B又对文件进行操作并将A的修改覆盖了,导致A实际保存的结果是B操作的结果;
2.**不可重复**: A对数据进行读取,在修改的过程中,B又对数据进行了读取并在A修改前进行了保存,当A再次读取文件进行结果验证的时候,发现啥都没做,结果就不对了。
其实就是对文件的操作没有保持原子性,这就需要通过互斥来保证同一时间只有一个线程能对文件进行操作;同时是谁先操作,谁继续操作(比如财务报销签字,先找部门领导,再找财务,顺序不对肯定签不了字,理论情况下),这就需要通过同步机制来保证。说了这么多概念,回到读写者问题。读者写者问题描述非常简单,有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者在读文件时写者也不去能写文件。![在这里插入图片描述](https://img-blog.csdnimg.cn/2e9e29b0bded455a8ccf7719a563b388.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdzE1MTMxMjc3MTgw,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center)思路: 首先分析以上情况,基于以上的介绍,只要多线程操作文件的,肯定需要保持原子性,即互斥;其次肯定是有先后顺序的,即先向缓存内写入实际数据,当缓存区有了数据后才可以读取,即同步。
1.对于互斥,在Windows编程中,有很多种方法:互斥锁(Mutex),关键段(Critical Section等,我在这里用的是互斥锁Mutex;
2.对于同步。先分析问题种需要怎样的顺序。很简单,首先必须先写入缓存,当写入完毕的时候,通知读取的线程缓存区有内容了,缓存线程进行读取;缓存线程都读取完毕后,由**最后一个**读取的线程通知写入线程可以继续写入。
以上是问题的分析。
下面是我的实现过程,直接上代码,更多的是记录如何使用这些API:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>//-------------------------------------------读写同步问题----------------------------
/*一个用户写入和多个用户读取问题读取的时候不所有用户不可以写入写入的时候所有用户不可以读取思路: 写入的时候先等待写入信号量(初始化时可以先写入的,即信号量有写入资源数);设置一个已读取用户的个数变量,每一个读取的用户读取前先和总户数作比较,确认自己是否是最后一个读取用户最后一个结束读文件的读者线程要负责通知读取线程可以继续写入。总结 : 1.写入的时候先等待写入信号,写入完释放读取信号2.读取的时候先读取写入信号,读取完再释放写入信号3.同时,对数据操作的时候添加互斥锁
*/
extern HANDLE g_Mutex;                      //缓存区访问互斥锁
HANDLE g_ReadSemaphore, g_WriteSemaphore;   //读写信号量
HANDLE thread[4];                           //读写线程句柄
const unsigned int g_Size=3;                //总用户数
const unsigned int g_BufferSize=8;          //总的写入次数
int buffer;                                 //读写的缓存区
int   g_Current_Read;                       //当前读取用户个数unsigned int __stdcall writeThread(PVOID pM){for (int i = 0; i < g_BufferSize; i++){        WaitForSingleObject(g_WriteSemaphore, INFINITE);WaitForSingleObject(g_Mutex, INFINITE);buffer = i;printf("Writer is writting.. write buffer is:%d\n", buffer);ReleaseMutex(g_Mutex);ReleaseSemaphore(g_ReadSemaphore, g_Size, NULL); }return 0;
}unsigned int __stdcall readThread(PVOID pM){while (true){WaitForSingleObject(g_ReadSemaphore, INFINITE);WaitForSingleObject(g_Mutex, INFINITE);printf("Reader %d  is reading.. read buffer is:%d\n", g_Current_Read,buffer);g_Current_Read++;ReleaseMutex(g_Mutex);if (g_Current_Read == g_Size ){               ReleaseSemaphore(g_WriteSemaphore, 1, NULL);g_Current_Read = 0;//这里要注意:这里判断的是自己(读取线程)是不是最后一个读取的线程//如果是,那么就要向写入线程发送信号,告诉它可以继续写入//同时将g_Current_Read清零,即当前位置计数。}}return 0;
}void useReadW(){g_ReadSemaphore = CreateSemaphore(NULL, 0, 3, NULL);//注意,CreateSemaphore的第2个参数是初始资源值,因为初始不能触发,必须保证写入线程发信号才能执行,所以这里置0//第3个参数是3,表示最大资源数为3,写入线程写入完毕后将资源加3,这三个读取线程可以读取缓存数据,因为已经实现了互斥,所以不会出问题//第4个参数是name,可以指定名称,当在多个进程种要实现线程的同步时,可以通过OpenSemaphore来打开此名字对应的信号锁。g_WriteSemaphore = CreateSemaphore(NULL, 1, 1, NULL);g_Mutex = CreateMutex(NULL, FALSE, NULL);//以上分别创建信号量、互斥锁//写入信号量g_WriteSemaphore初始资源为1(第2个参数),表示初始可以先写入,//其最大资源数也是1.这就侧面说明信号量也可以实现互斥,即信号量是一种特殊的互斥//这里的同步其实也可以用事件来实现,但是多个线程通知我觉得还是信号量方便一些thread[0] = (HANDLE)_beginthreadex(NULL, 0, writeThread, NULL, 0, NULL);thread[1] = (HANDLE)_beginthreadex(NULL, 0, readThread, NULL, 0, NULL);thread[2] = (HANDLE)_beginthreadex(NULL, 0, readThread, NULL, 0, NULL);thread[3] = (HANDLE)_beginthreadex(NULL, 0, readThread, NULL, 0, NULL);//初始同时启动读写线程,启动顺序没有要求,因为已经实现的同步//我查了以下,_beginthreadex内部其实调用的是CreateThread函数接口,//在此做了封转,保证了线程的安全性,建议用此方法。WaitForMultipleObjects(4, thread, TRUE, INFINITE);//此函数功能是让主线程阻塞,直到所有线程执行完毕后再继续//第1个参数是等待的线程数目//第2个参数的线程数组//第3个参数为true表示需要所有的线程都发出信号后才结束阻塞//第4个参数表示一直等待下去,不超时int i = 0;while (i < 4){CloseHandle(thread[i]);   //关闭读写线程句柄}CloseHandle(g_ReadSemaphore);CloseHandle(g_WriteSemaphore);  //关闭读写信号量句柄CloseHandle(g_Mutex);           //关闭互斥锁句柄
}

以下是运行的结果:

好了,今天就先记录到这里,有问题多谢指点!

windows多线程之读写同步(线程锁Mutex + 信号量Semaphore )相关推荐

  1. python多线程_【python多线程02】各种线程锁

    0x00 前言 本片文章讲述了小明同学在编写python多线程过程中遇到一些奇怪现象,小明根据这些奇怪现象挖掘背后的原因...通过遇到的问题,引申出全局解释器锁,同步锁,递归锁,信号量... 0x01 ...

  2. 多线程并发安全问题与线程锁

    一.多线程并发安全问题 二.什么是线程锁及分类 三.synchronized关键字 多线程并发安全问题 当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致操作临界资源的顺序出现混乱严重时可能 ...

  3. windows 多线程(五) 互斥量(Mutex)

    参考:http://blog.csdn.net/morewindows/article/details/7470936 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行 ...

  4. Python入门学习笔记13(线程锁与信号量)

    锁的作用是在多个线程访问同一个资源时对资源进行保护,防止多线程操作造成结果不解预测 1.互斥锁 import threadingnum = 0mutex = threading.Lock();def ...

  5. python 多线程 数据库死锁_python并发编程之多线程2死锁与递归锁,信号量等

    一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 这些永远在互相等待的进程称为死锁进程 如下就是死锁 ...

  6. Python笔记day40(并发)|守护线程、线程锁、信号量、事件、条件、定时器、队列、线程池

    1,内容回顾 # 正确的学习方法# input# output# correct 纠正# 线程# 线程是进程中的执行单位# 线程是cpu执行的最小单位# 线城之间资源共享# 线程的开启和关闭以及切换的 ...

  7. 线程、同步与锁——Mutex想说爱你不容易

    除了Lock().Monitor之外,我们最长用的就是Mutex了,但是玩不好Mutex就总会造成死锁或者AbandonedMutexException(我就玩的不怎么好,在并发性访问测试的时候总是遇 ...

  8. ReentrantLock+线程池+同步+线程锁

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

  9. java 多线程 串行 加锁_Java多线程(2)线程锁

    多线程访问同一个资源进行读写操作,就很容易出一些问题(比如我们常见的读者写者,生产者消费者模型)所以我们会选择对他们设置信号量或者加锁,来限制同一个时刻只有一个线程对某个对象进行操作. 多线程是一个蛮 ...

最新文章

  1. HAOI2011 Problem b
  2. 【转】Linux操作系统下/etc/hosts文件配置方法
  3. 【ABAP】获取后台Job相关状态
  4. thinkPHP源码目录介绍
  5. Row_number () over (partition by col1 order by col2)的用法
  6. 如何处理non-resolvable parent POM的错误
  7. vm+ubuntu联网
  8. ASP.NET Core中使用GraphQL - 第三章 依赖注入
  9. php与rest的关系,PHP与节点REST-API
  10. python 封装对象数据_Python数据库封装实现代码示例解析
  11. jQuery表格排序组件-tablesorter
  12. linux怎么下载ftp文件夹,命令行 - 如何在Linux上通过FTP递归下载文件夹
  13. Keras-YOLOV3-tensorflow制作训练自己的数据集
  14. orcale :SQL语句小测试select * from emp order by hiredate asc;
  15. angular--安全导航操作符 ( ?. )、非空断言操作符(!) (实用)
  16. eot文件html,html – 为什么IE8没有加载我的eot文件?
  17. 星星城堡童装加盟雾非雾
  18. Android6.0 按键流程(七)无线鼠标右键无效 -- Framework层
  19. 重读《由C#风潮想起的-给初学编程者的忠告》有感 (转载)
  20. uni-app学习笔记(一):HbuildX+uni-app搭建小程序项目

热门文章

  1. 搭建一个网站,需要好几种服务器吗?
  2. linux笔记(10):ubuntu环境下,基于SDL2运行lvgl+ffmpeg播放mp4
  3. stm32滴答计时器_第三讲 STM32 SysTick---系统滴答定时器
  4. CSS选择器,盒子模型及浮动
  5. elasticsearch:调用接口设置search.max_buckets的值
  6. Buckets On Hive
  7. 简述C和C++程序员学习历程
  8. 工业边缘网关-04配置静态IP地址
  9. HTML5+CSS大作业——丝绸之路网页设计(6页)
  10. 《网络科学导论》学习笔记——代表性网络的研究内容