
1.1线程同步概述
由于没有同步对象和操作系统监视特殊事件的能力,线程可能被迫使用副作用技术将自身与特殊事件同步. 如果不使用操作系统支持的线程同步技术,就会出现许多问题,例如: 分配不必要的CPU时间和浪费;在高优先级线程和低优先级线程之间,如果低线程负责信号重置任务,则重置可能永远不会执行.
关键部分: 在所有同步对象中,关键部分最容易使用,但只能用于在单个进程中同步线程. 关键部分一次仅允许一个线程访问数据区域. 另外,在这些同步对象中,只有关键部分不是内核对象,它不是由操作系统的低级组件管理的,并且不能使用句柄进行操作.
1. 在流程中创建一个关键部分,即在流程中分配CRITICAL_SECTION数据结构. 关键部分结构的分配必须是全局的,以便进程的不同线程可以访问它.
2. 在使用关键部分同步线程之前,必须调用InitializeCriticalSection初始化关键部分. 您只需要在释放资源之前对其初始化一次即可.
3. VOID EnterCriticalSection: 阻止功能. 当调用线程被授予所有权时,该函数返回. 换句话说,当调用线程无法获取指定关键部分的所有权时,该线程将进入睡眠状态,并且直到唤醒该线程后,系统才会为其分配CPU.
4. 在关键部分执行任务
5. BOOL LeaveCriticalSection: 非阻塞函数. 将当前线程的引用计数减一到指定的临界区;当使用计数变为零时,另一个等待此关键部分的线程将被唤醒.
6. 当不再需要关键部分时,请使用DeleteCriticalSection释放关键部分所需的资源. 该函数执行后,您将无法再使用EnterCriticalSection和LeaveCriticalSection,除非关键部分再次使用InitializeCriticalSection初始化.
1.2.2注意:
1. 关键部分一次只能访问一个线程. 在视图对关键部分数据进行操作之前,每个线程必须调用关键部分标志(即CRITICAL_SECTION全局变量)EnterCriticalSection. 将设置其他想要获得访问权限的线程. 在睡眠状态下,在被唤醒之前,系统将停止为它们分配CPU时间片. 换句话说,关键部分只能由一个线程拥有. 当然,当没有线程调用EnterCriticalSection或TryEnterCriticalSection时,关键部分不属于任何线程.
2. 当拥有关键部分所有权的线程调用LeaveCriticalSection放弃所有权时,系统仅唤醒一个正在等待的线程,赋予其所有权,其他线程继续休眠.
3. 请注意,对于拥有关键部分的线程,对该关键部分的每次EnterCriticalSection调用都会成功(此处重复调用也将立即返回),并将导致关键部分标志(即CRITICAL_SECTION全局变量)的引用计数增加一. 在另一个线程可以拥有关键节之前,拥有它的线程必须多次调用LeaveCriticalSection. 在引用计数降至零后,另一个线程可能拥有该临界区. 换句话说,在通常使用关键部分的线程中,应成对使用calSection和LeaveCriticalSection.
4. TryEnterCriticalSection
BOOL TryEnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection可以从函数声明中看到. EnterCriticalSection函数的返回值为VOID,此处为BOOL. 可以看出,对于TryEnterCriticalSection的调用,我们需要判断其返回值. 调用TryEnterCriticalSection时,如果指定的关键部分不属于任何线程(或未被任何调用线程调用),则此函数将访问该关键部分的权限授予调用线程,并返回TRUE;否则,返回TRUE. 但是,如果关键部分为A,则线程拥有它,并且它立即返回FALSE值. TryEnterCriticalSection和EnterCriticalSection之间的最大区别是TryEnterCriticalSection永远不会挂起线程.
);
1.3将线程与内核对象同步
关键部分非常适合序列化流程中的数据访问,因为它们很快. 但是我们可能希望将某些应用程序与计算机中发生的其他特殊事件或在其他进程中执行的操作进行同步. 关键区域无能为力. 您需要使用内核对象进行同步.
以下内核对象可用于同步线程:
1. 流程
2. 线程
3. 文件

4. 控制台输入
5. 文件更改通知
6. 互斥体,互斥体
7. 信号量,信号量
8. 事件(自动重置事件和手动重置事件),事件
9. 等待计时器(仅适用于Windows NT4或更高版本),等待计时器
每种类型的对象都可以处于以下两种状态之一: 信号状态和非信号状态. 例如,当进程或线程终止时,其内核对象会发出信号,而当它们创建并运行时,其内核对象将不会发出信号.
1.3.2内核对象同步应用程序
1. 当线程获得进程的内核对象句柄时,它可以: 更改进程的优先级,获得进程的退出代码;将线程与进程终止等同步.
2. 当获得线程的内核对象句柄时,它可以: 更改线程的运行状态,与线程的终止同步,等等.
3. 获取文件句柄时,还可以: 该线程可以与异步文件I / O操作等获得同步.
4. 控制台输入对象可用于使线程唤醒以执行相关的任务,等等.
5. 其他内核对象(文件更改通知,互斥量,信号量,事件,可等待计时器等)仅存在于同步对象中. 相应地,存在WIN32函数来创建,打开和关闭这些对象,并使线程与这些对象同步. 无法对这些对象执行其他操作.
1.3.3互斥锁的独特特性(另请参见附录中的实验)
互斥对象与所有其他内核对象不同,因为互斥对象由线程拥有. 所有其他同步对象都具有信号或没有信号,仅此而已. 除了记录当前信号状态的互斥对象外,请记住线程目前拥有它. 如果线程在获取互斥对象后终止(即使其成为非信号对象),则该互斥将被丢弃. 在这种情况下,互斥锁将永远保持无信号状态,因为没有其他线程可以通过调用ReleaseMutex来释放它.
当系统发现发生这种情况时,它将自动将互斥锁重新设置为发信号状态. 其他等待信号量的线程将被唤醒,但是该函数的返回值为WAIT_ABANDONED而不是常规的WAIT_OBJECT_0. 此时,其他线程可以知道互斥锁是否正常释放.
其他,互斥锁类似于CRITICAL_SECTION. 拥有互斥量的线程将在每次调用WaitForSingleObject时成功返回,但是互斥量的使用计数将增加. 同样,必须多次调用releaseMutex才能使引用计数为零,然后其他线程才能使用它.
问: 当线程异常终止而不释放所有权时,其他内核对象是否会重置其状态?如果将其重置,将不会有任何标记,这与普通版本没有什么不同,也就是说,它不会具有互斥体的return WAIT_ABANDONED属性吗?
[注意: 一个线程拥有一个内核对象,而一个线程拥有一个内核对象的所有权,这是不同的. 当一个线程拥有一个内核对象时,应该强调的是,当线程终止时,如果该线程碰巧可以访问内核对象,则该内核对象也将被丢弃,因为它的信号状态不能被重置. 线程拥有使用内核对象的权利,意味着线程可以调用某些功能windows 线程同步,访问内核对象或对该内核对象执行某些操作]
A: 请参阅附录后面的“讨论和实验1”.
1.3.4 WaitForSingleObject和WaitForMultipleObjects
线程主要使用两个函数来将它们设置为休眠状态,以等待内核对象发出信号: 两者都是阻塞函数.
DWORD WaitForSingleObject(

HANDLE hHandle,
DWORD dw毫秒
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE * lpHandles,
BOOL bWaitAll,
DWORD dw毫秒
WaitForSingleObject等待内核对象在指定时间内(dwMilliseconds)发出信号. 在这段时间内,如果等待的内核对象始终未发出信号,则调用线程将进入睡眠状态,否则继续执行. 在这段时间之后,线程继续运行. 该函数的返回值可以是: WAIT_OBJECT_0,WAIT_TIMEOUT,WAIT_ABANDONED(仅当内核对象是互斥锁时),WAIT_FAILED.
WaitForMultipleObjects与WaitForSingleObject相似,不同之处在于它要么等待指定列表(由lpHandles指定)中的多个对象(由nCount确定)被发信号,要么等待列表中的一个对象(由lpHandles指定)成为信号. 有一个信号(由bWaitAll确定).
WaitForSingleObject和WaitForMultipleObjects函数对特定的内核对象有重要的副作用-即,它们将决定是否更改内核对象的信号状态并根据不同的内核对象执行此类更改;这些副作用决定是否让一个或所有等待内核对象的进程或线程唤醒?
1. 对于进程和线程内核对象,这两个函数没有副作用. 也就是说,在发出进程或线程内核对象的信号后,它们将保持发出信号的状态. 这两个函数将不会尝试更改内核对象的信号状态. 这样,所有等待这些内核对象的线程都将被唤醒.
WaitForSingleObject函数检查指定对象的当前状态. 如果对象的状态为非信号状态,则调用线程进入等待状态. 在等待对象状态发出信号或超时间隔过去时,它不使用处理器时间.
该函数修改某些类型的同步对象的状态. 修改仅针对其信号状态导致函数返回的对象发生. 例如,信号量对象的数量减少一.
2. 对于互斥锁,自动重置事件和自动重置等待计时器对象,这两个功能会将其状态更改为无信号. 换句话说,一旦这些对象被发出信号并且唤醒了一个线程,这些对象将重置为非信号状态. 结果,只有一个等待线程唤醒,其他等待线程将继续休眠.
3. WaitForMultipleObjects函数还有一个非常重要的功能: 当bWaitAll在调用时为TRUE时,可以更改任何可更改的内核,然后将其发送给所有等待的对象. 没有任何对象被重置为无信号状态. 换句话说,bWaitAll参数为TRUE,并且WaitForMultipleObjects不会拥有单个对象的所有权,除非它可以拥有所有指定对象(由lpHandles指定)的所有权(它不能拥有所有权,也不会更改此对象的信号状态)宾语). 这是为了防止死锁. 换句话说,当bWaitAll为TRUE时,WaitForMultipleObjects将不会更改无需获取所有等待对象的所有权即可更改的内核对象的信号状态,并且不会唤醒以相同方式等待的任何线程--但是以其他方式等待的线程将被唤醒.
WaitForMultipleObjects函数确定是否满足等待条件. 如果未满足条件,则调用线程进入等待状态. 在等待标准满足时,它不占用处理器时间.
当bWaitAll为TRUE时,仅当所有对象的状态都设置为信号时,函数的等待操作才完成. 该功能不会修改指定对象的状态,直到所有对象的状态都已设置为已发出信号. 例如,可以发出互斥信号,但是直到其他对象的状态也被设置为信号时,线程才获得所有权. 同时,其他一些线程可能会获得该互斥锁的所有权,从而将其状态设置为非信号状态.
该函数修改某些类型的同步对象的状态. 仅对信号状态导致功能返回的一个或多个对象进行修改. 例如,信号量对象的数量减少一. 当bWaitAll为FALSE且多个对象处于信号状态时,该函数选择一个对象以满足等待(选择哪个对象?神知道!);未选择对象的状态不受影响.
1.3.5事件或计时器的自动或手动重置
1. 自动重置: 当发出内核对象信号时windows 线程同步,只有一个线程可以获取它. 一旦获得该线程,内核对象将变为非信号状态,其他等待线程将继续休眠. 自动重置无信号状态的功能由Wait类功能实现.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-146872-1.html
好甜
装备落后的体现以及人员素质低于日本人的体现