多线程第七篇:互斥和同步总结

2024-08-24 16:18

本文主要是介绍多线程第七篇:互斥和同步总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   同步:多个线程(进程)之间有严格的先后顺序,一个线程(进程)的执行,依赖于另一个.
   互斥:多个线程(进程)没有先后顺序,谁抢到算谁的.
 

注意:线程的创建和执行是分开的,并不是创建后立即执行,而是创建后,等待cpu调度.

window中的四种线程(进程)间同步与互斥.
criticalSection,mutex,event,semaphore

criticalSection:
     1.中文名称临界区或者关键段,用于线程间互斥.
     2.进入和离开必须成对出现.
     3.不是内核对象,不能用于进程间互斥,只能用于线程间互斥
     4.由于不是内核级对象,所以速度较快,效率较高.
使用:
     1.InitializeCriticalSection
     2.EnterCriticalSection
     3.LeaveCriticalSection
注意事项:
     临界区为子线程所有,主线程中使用临界区并不能实现互斥.


mutex:
     1.互斥区,用于线程(进程)间互斥
     2.记录拥有着,可以处理遗弃问题,当前使用该互斥区的线程(进程)占有该互斥区,并且,其他线程(进程)不能使用.
     3.可以在线程A中waitforsignalobject,在线程B中release.
     4.是内核对象,可以进行进程间互斥.
使用:
     1.CreateMutex或者OpenMutex
     2.ReleaseMutex 
     3.WaitForSingleObject
     4.CloseHandle
event:
     1.事件,用于线程(进程)间同步和互斥.
     2.是内核对象,不具有拥有权,即可以由一个线程(进程)触发,而由另一个线程(进程)恢复.
使用:
     1.CreateEvent
     2.SetEvent
     3.ResetEvent
     4.PulseEvent
     5.WaitForSingleObject
     6.CloseHandle

semaphore:
     1.信号量,用于线程(进程)间同步和互斥.
     2.是内核对象,不具有拥有权,可以在不同的线程(进程)中进行PV操作.
使用:
     1.CreateSemaphore 或OpenSemaphore
     2.ReleaseSemaphore(+n)
     3.WaitForSingleObject(-1)
     4.CloseHandle

遗弃问题:
     由于临界区是线程级别使用的,线程的操作都是由主线程控制的,当一个正在使用临界区的线程突然崩溃会怎么样呢?由于临界区会记录使用的线程,所以同样可以处理遗弃问题.

遗弃问题:
     由于进程(线程)突然死亡,而没有进行任何善后处理,这样会造成资源永远被占用,需要一种方法来解决.
 
解决之道
     当mutex使用者突然死了,那么mutex归零,等待其他使用者占有然后使用.
为什么event和semaphore不可以:
     因为event和semaphore并不记录其使用者,他的使用者死了event和semaphore并不知道,他只知道自己被使用,等待被释放.
     如果event和semaphore的使用者突然死亡,而其进程都在等待event和semaphore可用,那么这就造成了死锁.


为什么mutex和临界区(critical_section)不能进行同步:
   因为mutex和critical不能再主线程中使用,而信号量和事件都可以在主线程中使用.
   回忆一下,我们每次进行线程间同步的时候,总是先在主线程先设置事件或者信号量的状态,然后再在线程中设置,这样线程就可以使得线程有先后顺序了,即实现同步.核心在于主线程总是第一个执行,然后再执行子线程,这样就可以有先后顺序,如果不在主线程中设置,只是让子线程进行同步,也可以这需要一个全局变量,来进行检测是不是该这个线程执行.

我们用临界区+全局变量来实现一个线程同步:
#include <iostream>
#include <windows.h>
#include <process.h>
int g_count = 0;
CRITICAL_SECTION all;
unsigned int __stdcall producer (void *)
{
int ID = 0;
bool flage = true ;
while ( flage   ){
EnterCriticalSection (&all );
if ( g_count == ID ){
std ::cout << "producer"<< std ::endl ;
flage = false ;
g_count ++;
}
LeaveCriticalSection (&all );
}
return 0;
}
unsigned int __stdcall consumer (void *)
{
int ID = 1;
bool flage = true ;
while ( flage   ){
EnterCriticalSection (&all );
if ( g_count == ID ){
std ::cout << "consumer"<< std ::endl ;
flage = false ;
}
LeaveCriticalSection (&all );
}
return 0;
}
int main ()
{
InitializeCriticalSection(& all );
HANDLE hproducer = (HANDLE ) _beginthreadex( NULL ,0,producer , NULL,0, NULL );
HANDLE hconsumer = (HANDLE ) _beginthreadex( NULL ,0,consumer , NULL,0, NULL );
WaitForSingleObject( hproducer ,INFINITE );
WaitForSingleObject( hconsumer ,INFINITE );
return 0;
}

扩展:
      可不可以让信号量和事件实现遗弃呢? 
      当然可以,我们可以在线程调用信号量或事件的时候,在内核对象中添加该进程号.在进程表或其他地方注册一个回调函数,此函数功能是当该进程或线程崩溃的时候,通知相关内核对象(信号量内核对象或者事件内核内核对象),此线程已崩溃,删除该线程相关信息.
     此机制类似于epoll机制,有兴趣可以了解一下.


这篇关于多线程第七篇:互斥和同步总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102972

相关文章

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Linux线程同步/互斥过程详解

《Linux线程同步/互斥过程详解》文章讲解多线程并发访问导致竞态条件,需通过互斥锁、原子操作和条件变量实现线程安全与同步,分析死锁条件及避免方法,并介绍RAII封装技术提升资源管理效率... 目录01. 资源共享问题1.1 多线程并发访问1.2 临界区与临界资源1.3 锁的引入02. 多线程案例2.1 为