C++ 线程的学习---线程同步
因为是学习篇,写下是为了个人的学习与理解。故参考其他文章为多。
- 为什么需要线程同步?
在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。
如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。
为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。
- 线程之间通信的两个基本问题是互斥和同步
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指对于共享的操作系统资源(指的是广义的”资源”,而不是Windows的.res文件,譬如全局变量就是一种共享资源),在各线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源
- 线程互斥是一种特殊的线程同步。
实际上,互斥和同步对应着线程间通信发生的两种情况:
当有多个线程访问共享资源而不使资源被破坏时;
当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。
- 从大的方面讲,线程的同步可分用户模式的线程同步和内核对象的线程同步两大类
用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快,适合于对线程运行速度有严格要求的场合。
内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象,使用时必须将线程从用户模式切换到内核模式,而这种转换一般要耗费近千个CPU周期,因此同步速度较慢,但在适用性上却要远优于用户模式的线程同步方式。
- 在WIN32中,同步机制主要有:事件(Event); 信号量(semaphore); 互斥量(mutex); 临界区(Critical section)
文档参考: C++线程同步的四种方式(Windows)
代码示例:
Project 1:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std; struct RandomSum {
DWORD a;
DWORD b;
}; int main()
{
//srand((unsigned int)time(NULL));
cout << "inside process 1" << endl; HANDLE hEvent1 = CreateEvent(NULL, FALSE, TRUE, "MyEvent1"); //TRUE=>初始状态是有信号的
HANDLE hEvent2 = CreateEvent(NULL, FALSE, FALSE, "MyEvent2"); //FALSE=>初始状态是没有信号的 HANDLE create_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, 1024 * 1024, "data");
if (create_file_mapping_handle == NULL) {
printf("Cannot create file mapping. Error code: %d", GetLastError());
return 0;
} unsigned char* pData = (unsigned char*)MapViewOfFile(create_file_mapping_handle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(create_file_mapping_handle);
return 0;
} //create new process
PROCESS_INFORMATION process2;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess("D:\\Project 2.exe", NULL,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &process2)) {
printf("Cannot create process.\n");
return 0;
}
CloseHandle(process2.hThread);
CloseHandle(process2.hProcess);
int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
hEvent1, // handle to mutex
INFINITE); // no time-out interval if (dwWaitResult == WAIT_OBJECT_0) {
cout << "am intrat in sender process si scriu in file mapping" << endl;
RandomSum test; DWORD randomNumber = rand() % 50;
test.a = randomNumber;
test.b = 2 * test.a;
memcpy(pData, &test, sizeof(RandomSum));
cout << "in process 1: " << "a = " << test.a << " b= " << test.b << endl;
cout << "last cout" << endl;
SetEvent(hEvent2);
} ++counter;
}
UnmapViewOfFile(pData);
CloseHandle(create_file_mapping_handle);
CloseHandle(hEvent1);
CloseHandle(hEvent2);
//getchar();
return 0;
}
Project 2:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std; struct RandomSum {
DWORD a;
DWORD b;
}; int main()
{
cout << "inside process2" << endl;
//srand((unsigned int)time(NULL)); cout << "something new in process2" << endl;
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, "MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, "MyEvent2"); LPCWSTR data = L"data";
HANDLE hData = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "data"); unsigned char* pData = (unsigned char*)MapViewOfFile(hData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(hData);
return 0;
} int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
hEvent2, // handle to mutex
INFINITE); // no time-out interval
if (dwWaitResult == WAIT_OBJECT_0) {
cout << "a inceput procesul 2" << endl;
RandomSum test; memcpy(&test, pData, sizeof(RandomSum)); cout << "a is " << test.a << " and b is " << test.b << endl;
SetEvent(hEvent1);
}
++counter; }
UnmapViewOfFile(pData);
CloseHandle(hData);
CloseHandle(hEvent1);
CloseHandle(hEvent2);
//getchar();
}
更多样本请参阅: https://stackoverflow.com/a/65084216/11128312
C++ 线程的学习---线程同步的更多相关文章
- java线程API学习 线程池ThreadPoolExecutor(转)
线程池ThreadPoolExecutor继承自ExecutorService.是jdk1.5加入的新特性,将提交执行的任务在内部线程池中的可用线程中执行. 构造函数 ThreadPoolExecut ...
- Windows API学习---线程与内核对象的同步
前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...
- Java八个并发学习——线程同步工具CyclicBarrier
本文是一篇文章对网络的研究摘要,感谢您的无私分享. CyclicBarrier 类有一个整数初始值,此值表示将在同一点同步的线程数量.当当中一个线程到达确定点,它会调用await() 方法来等待其它线 ...
- Java学习之多线程(线程安全问题及线程同步)
一.线程安全问题产生前提:1.多线程操作共享数据2.线程任务中有多条代码 class Ticket implements Runnable { //2.共享数据 private int num = 1 ...
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- 关于协程的学习 & 线程栈默认10M
先看的这篇文章:http://blog.csdn.net/qq910894904/article/details/41699541 以nginx为代表的事件驱动的异步server正在横扫天下,那么事件 ...
- 菜鸟之旅——学习线程(Task)
前面两篇回顾线程和线程池的使用方法,微软在.NET4.5推出了新的线程模型-Task.本篇将简单的介绍Task的使用方法. Task与线程 Task与线程或者说线程池关系紧密,可以说是基于线程池实现的 ...
- Java线程机制学习
前面的文章中总结过Java中用来解决共享资源竞争导致线程不安全的几种常用方式: synchronized: ReentrantLock: ThreadLocal: 这些都是在简单介绍了基本用法的基础上 ...
- Python学习---线程/协程/进程学习 1220【all】
Python学习---线程基础学习 Python学习---线程锁/信号量/条件变量同步1221 Python学习---同步条件event/队列queue1223 Python学习---进程 1225 ...
- Java并发读书笔记:线程安全与互斥同步
目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...
随机推荐
- [转帖]Jmeter学习笔记(二十三)——生成HTML性能报告
https://www.cnblogs.com/pachongshangdexuebi/p/11759316.html 有时候我们写性能报告的时候需要一些性能分布图,JMeter是可以生成HTML性能 ...
- [转帖]【jmeter】BeanShell用法详细汇总
一.什么是Bean Shell BeanShell是用Java写成的,一个小型的.免费的.可以下载的.嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k. B ...
- 【转帖】nginx变量使用方法详解-1
https://www.diewufeiyang.com/post/575.html Nginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序 ...
- [转帖]Kafka 核心技术与实战学习笔记(八)kafka集群参数配置(下)
一.Topic级别参数 Topic的优先级: 如果同时设置Topic级别参数和全局Broker参数,那么Topic级别优先 消息保存方面: retention.ms:规定Topic消息保存时长.默认是 ...
- [转帖]Docker:Python环境Docker镜像瘦身
https://www.jianshu.com/p/c0ad13e0be85 关键字:Docker,Python 原始镜像 封装一个Python 3.7的环境并且安装Python依赖包实现一个机器学习 ...
- 【转帖】磁盘IOPS的计算
计算磁盘IOPS的三个因素: 1.RAID类型的读写比 不同RAID类型的IOPS计算公式: RAID类型 公式 RAID5.RAID3 Drive IOPS=Read IOPS + 4*Write ...
- [转帖]ebpf 月报 - 2023 年 1 月
https://segmentfault.com/a/1190000043355631 本刊物旨在为中文用户提供及时.深入.有态度的 ebpf 资讯. 如果你吃了鸡蛋觉得好吃,还想认识下蛋的母鸡,欢迎 ...
- 【记录一个问题】golang 中的 ecdsa(椭圆曲线加密) 算法很慢,因为用到了系统调用
代码中使用了椭圆曲线算法来签名,实际运行中发现不够快: func BenchmarkECDSA(b *testing.B) { privateKeyInst, err := parseSignatur ...
- P9779_[HUSTFC 2023] 不定项选择题_题解
rt 题目 有一道共 n 个选项的不定项选择题,它的答案至少包含一个选项,由于题目与选项的内容晦涩难懂,你打算通过尝试每一种可能的答案来通过这道题. 初始时所有选项都没有被勾选,你可以执行任意次下述操 ...
- 解决:VScode中 import 后出现no module的问题
问题: ModuleNotFoundError: No module named 'xxx' 除去没有安装包的问题 这个问题还是挺难受的,pycharm和终端都可以运行,只有vscode报错 方法一: ...