Windows提高_2.3第三部分:内核区同步

第三部分:内核区同步

等待函数(WaitForObject)

等待函数的形式

  • 单个:WaitForSingleObject
  • 多个:WaitForMultipleObjects

一个可以被等待的对象通常由两种状态,分别是:

  • 可等待(激发态)(有信号):等待函数【不会阻塞】
  • 不可等待(非激发态)(无信号):等待函数需要等待一定时长并【阻塞】

等待函数的副作用:

  • 改变被等待对象的信号状态
#include <iostream>
#include <windows.h>
?
// 工作线程
DWORD WINAPI WorkerThread(LPVOID lpThreadParameter)
{
    // 输出 0 ~ 99
    for (int i = 0; i < 1000; ++i)
    {
        printf("%d\n", i);
    }
?
    return 0;
}
?
int main()
{
    HANDLE Threads[3] = { 0 };
?
    // 创建两个线程
    Threads[0] = CreateThread(NULL, NULL, WorkerThread, NULL, NULL, NULL);
    Threads[1] = CreateThread(NULL, NULL, WorkerThread, NULL, NULL, NULL);
    Threads[2] = CreateThread(NULL, NULL, WorkerThread, NULL, NULL, NULL);
?
    // 函数返回的两种情况
    // 1. 被等待对象处于有信号状态
    // 2. 等到超时函数会返回,但是等待失败
?
    // 等待两个线程退出
    // 1. 一个可以被等待的内核对象
    // 2. 等待时长,如果是-1 表示一直等待
    // WaitForSingleObject(ThreadHandles[0], INFINITE);
    // WaitForSingleObject(ThreadHandles[1], INFINITE);
?
    // 等待多个内核对象
    // 1. 需要等待多少个内核对象
    // 2. 内核对象句柄的数组
    // 3. 是否等待所有内核对象编程变成有信号的
    // 4. 等待的时长,单位是毫秒
    // WaitForMultipleObjects(2, ThreadHandles, TRUE, INFINITE);
?
    // 有任何一个执行完毕,另外一个就不执行了
    WaitForMultipleObjects(3, Threads, FALSE, INFINITE);
?
    // 等待函数的副作用:修改被等待对象的信号状态
?
    return 0;
}

互斥体(Mutex)

  • 特点:拥有临界区的线程拥有者概念,但是线程崩溃不会死锁,执行较慢
  • 函数
    • 创建:CreateMutex,如果第二个参数是FALSE,那么就是可等待
    • 打开:OpenMutex
    • 保护:WaitForSingleObject: 把互斥体置为不可等待
    • 释放:ReleaseMutex把互斥体置为可等待
    • 关闭:CloseHandle
// 1. 创建一个互斥体内核对象
// - 安全属性,初始状态,名称
HANDLE Mutex = CreateMutex(NULL, FALSE, L"Mutex");
?
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter)
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
    {
        // 2. 使用等待函数对互斥体进行等待,当互斥体处于激发态就会等待成功
        // 当等待成功时,会将互斥体置为无信号状态
        WaitForSingleObject(Mutex, INFINITE);
        g_Number++;
        // 3. 执行完代码之后需要恢复有信号状态
        ReleaseMutex(Mutex);
    }
    return 0;
}

事件(Event)

  • 特点:可以手动选择是否产生副作用,如果设置为手动状态,那么就不产生副作用
  • 函数:
    • 创建:CreateEvent()
    • 打开:OpenEvent()
    • 保护:WaitForSingleObject()
    • 设置为非激发态:ResetEvent()
    • 退出(设置为激发态):SetEvent()
    • 关闭:CloseHandle
// 1. 创建一个事件内核对象
// - 安全属性,是否自动,初始状态,名称
HANDLE Event = CreateEvent(NULL, FALSE, TRUE, L"Event");
// HANDLE Event = CreateEvent(NULL, TRUE, TRUE, L"Event");
?
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter)
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
    {
        // 注意:如果使用手动模式,等待函数就没有副作用
        // 可以使用 ResetEvent 手动设置信号状态,但是没有意义
        // 原因是 ResetEvent 本身不是一个原子操作
?
        // 2. 使用等待函数对事件进行等待,当事件处于激发态就会等待成功
        // 当等待成功时,会将事件置为无信号状态
        WaitForSingleObject(Event, INFINITE);
        g_Number++;
        // 3. 执行完代码之后需要恢复有信号状态
        SetEvent(Event);
    }
    return 0;
}

信号量

  • 特点:有多把锁,可以控制活动线程的数量,没有线程拥有者概念。
  • 如果锁的最大个数是1,则用法和互斥体类似
  • 函数:
    • 创建:CreateSemaphore
    • 打开:OpenSemaphore
    • 上锁:WaitForSingleObject
    • 解锁:ReleaseSemaphore
    • 关闭:CloseHandle
// 1. 创建一个信号量内核对象
// - 安全属性,当前信号,最大信号,名称
HANDLE Semaphore = CreateSemaphore(NULL, 1, 1, L"Semaphore");
?
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter)
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
    {
        // 2. 使用等待函数对信号量进行等待,当信号个数>1表示可等待
        // 当等待成功时,会将信号个数 -1
        WaitForSingleObject(Semaphore, INFINITE);
        g_Number++;
        // 3. 执行完代码之后需要将信号个数 +1
        // 信号量对象,+几个信号,之前有多少个信号
        ReleaseSemaphore(Semaphore, 1, NULL);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ltyandy/p/10938205.html

时间: 2024-10-14 00:13:46

Windows提高_2.3第三部分:内核区同步的相关文章

读书笔记----《windows核心编程》第三章 内核对象1(句柄与安全性)

最近一直没有更新博客,因为一直在想一个问题,内核对象这一章内容很多很重要,自己没有掌握好也没有把握写好这一章,最后还是决定能写多少写多少,一面写一面学,后续学到新的再更新吧; <windows核心编程>提了几种内核对象: 访问令牌对象:与windows的安全性有关,目前不是很懂,了解后再写; 事件对象: Event对象,可跨进程同步; 由CreateEvent创建; 文件对象: File对象,比较常见; 由CreateFile创建; 文件映射对象: 通过文件映射可以方便的操作文件(如同文件数据

Windows提高_2.1第一部分:线程

第一部分:线程 什么是线程? 线程其实可以理解为一段正在执行中的代码,它最少由一个线程内核对象和一个栈组成. 线程之间是没有从属关系的,同一进程下的所有线程都可以访问进程内的所有内容. 主线程其实是创建进程时创建的线程,主线程一旦退出,所有子线程也会退出. 创建一个线程 #include <stdio.h> #include <process.h> #include <windows.h> ? // 线程函数 DWORD WINAPI WorkerThread(LPVO

Windows提高_2.2第二部分:用户区同步

第二部分:用户区同步 同步和互斥 同步:就是按照一定的顺序执行不同的线程 互斥:当一个线程访问某一资源的时候,其它线程不能同时访问 多线程产生的问题 #include <stdio.h> #include <windows.h> ? // 全局变量,被不同的线程访问和修改 int g_Number = 0; ? DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter) { // 为 g_Number 自增 100000 次 for (int

Windows核心编程之核心总结(第三章 内核对象)(2018.6.2)

学习目标 第三章内核对象的概念较为抽象,理解起来着实不易,我不断上网找资料和看视频,才基本理解了内核对象的概念和特性,其实整本书给我的感觉就是完整代码太少了,没有多少实践的代码对内容的实现,而且书本给的源码例子,有太多我们不知道的知识,并且这些知识对本章主要内容来说是多余的,所以我们理解起来也非常困难.为了更好的学习这章,我补充了一些辅助性内容.这一章的学习目标:1.Windows会话和安全机制2.什么是内核对象?3.使用计数和安全描述符4.内核对象句柄表5.创建内核对象6.关闭内核对象7.跨进

Windows内核原理-同步IO与异步IO

目录 Windows内核原理-同步IO与异步IO 背景 目的 I/O 同步I/O 异步I/O I/O完成通知 总结 参考文档 Windows内核原理-同步IO与异步IO 背景 在前段时间检查异常连接导致的内存泄漏排查的过程中,主要涉及到了windows异步I/O相关的知识,看了许多包括重叠I/O.完成端口.IRP.设备驱动程序等Windows下I/O相关的知识,虽然学习到了很多东西,但是仍然需要自顶而下的将所有知识进行梳理. 目的 本片文章主要讲解同步I/O与异步I/O相关知识,希望通过编写本篇

Windows API 编程学习记录&lt;三&gt;

恩,开始写API编程的第三节,其实马上要考试了,但是不把这节写完,心里总感觉不舒服啊.写完赶紧去复习啊       在前两节中,我们介绍了Windows API 编程的一些基本概念和一个最基本API函数 MessageBox的使用,在这节中,我们就来正式编写一个Windows的窗口程序. 在具体编写代码之前,我们必须先要了解一下API 编写窗口程序具体的三个基本步骤:             1. 注册窗口类:             2.创建窗口:             3.显示窗口: 恩,

Windows核心编程笔记(7)----内核模式下的线程同步

1.内核对象同步与用户模式下同步对比 使用内核对象的唯一缺点就是性能,调用内核对象函数时,调用线程必须从用户模式切换到内核模式,这种切换是相当 耗时的. 内核对象(进程.线程.作业)要么处于触发态,要么处于未触发状态.进程内核对象在创建时总是处于未触发状态, 当进程终止时,操作系统会自动使进程内核对象变成触发状态.当进程内核对象处于触发状态后,将永远保持这种状态, 再也不能变回未触发状态. 2.等待内核对象 WaitForSingleObject等待单个内核对象,WaitForMultipleO

前端编程提高之旅(三)----浏览器兼容之IE6

在爱奇艺实习期间,乐帝主要负责移动端活动页面的制作,由于移动浏览器是随着智能手机兴起的,这就决定了移动端不会重蹈浏览器兼容问题的覆辙,一开始就比较好的支持web标准,而纵观整个互联网行业,移动web开发还处于起步阶段,在很长一段时间pc端web作为主要的服务形式还会继续.从小来说作为一名前端开发人员,不了解浏览器兼容也会贻笑大方.这篇文章基于<IE7web标准之道>,对浏览器兼容做一个概览.    时间到了2014年,大概很少人会想到IE7发布之后,时隔这么多年IE6仍然占据市场7%的浏览器份

liunx内核移植(三)——内核、驱动、应用程序、根文件系统的关系

一:驱动属于内核的一部分 (1)驱动就是内核中的硬件设备管理模块 (2)驱动工作在内核态. (3)驱动程序故障可能导致整个内核崩溃 (4)驱动程序漏洞会使内核不安全 二:应用程序和内核的关系 (1)应用程序不属于内核,而是在内核之上的 (2)应用程序工作在用户态,是受限制的. (3)应用程序故障不会导致内核崩溃 (4)应用程序通过内核定义的API接口来调用内核工作,也就是说应 用程序依赖于内核,比如C语言的标准库就属于一个应用程序,所以在 内核当中不能使用C标准库,而是要使用liunx内核中的库