多线程信号量

本文详细介绍了Windows API中的同步机制,包括如何使用CreateEvent创建事件、SetEvent和ResetEvent设置及重置事件状态,以及WaitForSingleObject等待事件。同时探讨了SuspendThread和ResumeThread函数如何挂起和恢复线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent() 来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待 其变为有信号.

相关函数

WaitForSingleObject
DWORD WaitForSingleObject( 
HANDLE hHandle, 
DWORD dwMilliseconds 
);

      参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是时间间隔。如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。

       WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。

CreateEvent
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
BOOL bManualReset,// 复位方式
BOOL bInitialState,// 初始状态
LPCTSTR lpName // 对象名称
);

lpEventAttributes:
        [输入]一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
bManualReset:
       [输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。
bInitialState:
       [输入]指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
lpName:
       [输入]指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。
       如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。
       如果lpName为NULL,将创建一个无名的事件对象。
       如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。


SuspendThread和ResumeThread

        使用 SuspendThread 和 ResumeThread 函数(Windows API 或 CWinThread 类成员函数),线程可以挂起或恢复另一个线程的运行。当线程处于挂起状态时,线程不会被调度运行。SuspendThread 函数将当前线程的挂起次数加 1。若该值的挂起次数大于 0,则该线程不运行。ResumeThread 函数将当前线程的挂起次数减 1。当该值为 0 时,线程恢复运行,否则线程仍处于挂起状态。如果将线程创建在挂起状态,那么在调用 ResumeThread  恢复执行之前可以完成对线程状态的初始化工作。
        另外可通过调用 Sleep 或 SleepEx 函数暂时挂起当前线程一段指定时间。它常用于线程与用户的交互中,通过延迟执行线程足够长的时间让用户观察其结果。在睡眠期间线程不会被调度执行。

 

 

 

 

在 Java 多线程编程中,信号量(Semaphore)是一种用于控制对共享资源访问的同步机制。它通过维护一定数量的许可(permits),决定线程是否可以继续执行。当线程尝试获取一个许可时,如果没有可用许可,则会被阻塞,直到其他线程释放许可[^3]。 ### 基本使用方式 Java 中的 `java.util.concurrent.Semaphore` 类提供了信号量的功能。以下是创建和使用信号量的基本步骤: 1. **初始化信号量**:构造函数接受两个参数,许可数量和是否公平策略。 2. **获取许可**:调用 `acquire()` 方法,如果当前有许可可用,则减少一个许可;否则线程进入等待状态。 3. **释放许可**:调用 `release()` 方法,将许可数量增加一。 ```java import java.util.concurrent.Semaphore; public class SemaphoreExample { private static final int NUM_THREADS = 5; private static final int MAX_PERMITS = 2; public static void main(String[] args) { // 创建一个具有两个许可的信号量 Semaphore semaphore = new Semaphore(MAX_PERMITS); for (int i = 0; i < NUM_THREADS; i++) { new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + " 正在尝试获取信号量"); semaphore.acquire(); // 获取信号量许可 System.out.println(Thread.currentThread().getName() + " 已获得信号量"); // 模拟工作时间 Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); // 释放信号量 System.out.println(Thread.currentThread().getName() + " 已释放信号量"); } }).start(); } } } ``` ### 使用场景 - **资源池管理**:例如数据库连接池,限制同时使用的连接数。 - **限流控制**:在高并发系统中,防止系统过载。 - **互斥锁替代品**:允许多个线程同时访问共享资源,但限制最大并发数。 ### 注意事项 - 信号量不保证线程安全的数据操作,仅控制访问数量。 - 应该始终在 `finally` 块中释放许可,以确保即使发生异常也能释放资源[^3]。 通过合理设置许可数量以及选择适当的获取与释放策略,可以有效地实现复杂的线程协作逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值