因为是学习篇,写下是为了个人的学习与理解。故参考其他文章为多。

  • 为什么需要线程同步?

在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。
     如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。
     为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。

  • 线程之间通信的两个基本问题是互斥和同步

           线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

           线程互斥是指对于共享的操作系统资源(指的是广义的”资源”,而不是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++ 线程的学习---线程同步的更多相关文章

  1. java线程API学习 线程池ThreadPoolExecutor(转)

    线程池ThreadPoolExecutor继承自ExecutorService.是jdk1.5加入的新特性,将提交执行的任务在内部线程池中的可用线程中执行. 构造函数 ThreadPoolExecut ...

  2. Windows API学习---线程与内核对象的同步

    前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...

  3. Java八个并发学习——线程同步工具CyclicBarrier

    本文是一篇文章对网络的研究摘要,感谢您的无私分享. CyclicBarrier 类有一个整数初始值,此值表示将在同一点同步的线程数量.当当中一个线程到达确定点,它会调用await() 方法来等待其它线 ...

  4. Java学习之多线程(线程安全问题及线程同步)

    一.线程安全问题产生前提:1.多线程操作共享数据2.线程任务中有多条代码 class Ticket implements Runnable { //2.共享数据 private int num = 1 ...

  5. Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  6. 关于协程的学习 & 线程栈默认10M

    先看的这篇文章:http://blog.csdn.net/qq910894904/article/details/41699541 以nginx为代表的事件驱动的异步server正在横扫天下,那么事件 ...

  7. 菜鸟之旅——学习线程(Task)

    前面两篇回顾线程和线程池的使用方法,微软在.NET4.5推出了新的线程模型-Task.本篇将简单的介绍Task的使用方法. Task与线程 Task与线程或者说线程池关系紧密,可以说是基于线程池实现的 ...

  8. Java线程机制学习

    前面的文章中总结过Java中用来解决共享资源竞争导致线程不安全的几种常用方式: synchronized: ReentrantLock: ThreadLocal: 这些都是在简单介绍了基本用法的基础上 ...

  9. Python学习---线程/协程/进程学习 1220【all】

    Python学习---线程基础学习 Python学习---线程锁/信号量/条件变量同步1221 Python学习---同步条件event/队列queue1223 Python学习---进程 1225 ...

  10. Java并发读书笔记:线程安全与互斥同步

    目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...

随机推荐

  1. [转帖]TLB缓存是个神马鬼,如何查看TLB miss?

    https://zhuanlan.zhihu.com/p/79607142 介绍TLB之前,我们先来回顾一个操作系统里的基本概念,虚拟内存. 虚拟内存 在用户的视角里,每个进程都有自己独立的地址空间, ...

  2. [转帖]查看oracle中表的索引

    oracle中表的索引信息存在 user_indexes 和 user_ind_columns 两张表里面,其中 user_indexes 系统视图存放是索引的名称以及该索引是否是唯一索引等信息, u ...

  3. [转帖]Rust在windows下安装以后cargo build Error: linker `link.exe` not found

    D:\rust\runoob-greeting\greeting>cargo build error: linker `link.exe` not found | = note: 系统找不到指定 ...

  4. [转帖]xsos - Summarize system info from sosreports

    https://github.com/ryran/rsar I'M LOOKING FOR RSAR SCREEN SHOTS INTRO INSTALLATION EXAMPLES IN ACTIO ...

  5. mysql 获取 今天是今年的第几天, 以及 还有多少天元旦的方法

    1. 获取今天是这一年的第几天 select dayofyear(curdate()); 或者是 select dayofyear(now()); 2. 获取还有多少天元旦的方法 select dat ...

  6. 什么是PWA 应用?核心技术有哪些

    在国内由于小程序的风生水起,PWA 应用在国内的状况一直都不是很好,PWA 和小程序有很多的相似性,但是 PWA 是由谷歌发起的技术,小程序是微信发起的技术,所以小程序在国内得到了大力的扶持,很快就在 ...

  7. Vue3中shallowReactive和shallowRef对数据进行非深度监听

    1.Vue3 中 ref 和 reactive 都是深度监听 默认情况下, 无论是通过 ref 还是 reactive 都是深度监听. 深度监听存在的问题: 如果数据量比较大,非常消耗性能. 有些时候 ...

  8. 小程序跳转到h5页面无法获取参数

    在小程序中,遇见这样一个需求: 小程序(携带token)跳转到H5页面: 在H5端取token;将token作为参数: 然后返回来的信息, 这里遇见一个问题,在created中无法获取地址栏的参数: ...

  9. 【小实验】golang的if比较中的string/[]byte转换会被编译器优化

    之前做了实验,[]byte类型使用string()进行转换的时候,会产生拷贝.see: [小测试]golang中使用string()来转换[]byte数组产生了拷贝 不过今天又有了新的认识.请先看下面 ...

  10. iframe 框架技术

    隐性转发 <!doctype html> <html lang="zh_CN"> <head> <meta charset="u ...