b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

ccriticalsection 调用 2次_递归 2次调用_layoutsubviews 调用2次(2)

电脑杂谈  发布时间:2019-07-13 03:09:05  来源:网络整理

在多同步对象上等待

KeWaitForMultipleObjects函数用于同时等待一个或多个同步对象。该函数调用方式如下:

ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
LARGE_INTEGER timeout;
NTSTATUS status = KeWaitForMultipleObjects(count,
        objects,
        WaitType,
        WaitReason,
        WaitMode,
        Alertable,
        &timeout,
        waitblocks);

ccriticalsection 调用 2次_递归 2次调用_layoutsubviews 调用2次

在这里,objects指向一个指针数组,每个数组元素指向一个同步对象,count是数组中指针的个数。count必须小于或等于MAXIMUM_WAIT_OBJECTS值(当前为64)。这个数组和它所指向的所有对象都必须在非分页内存中。WaitType是枚举类型,其值可以为WaitAll或WaitAny,它指出你是等到所有对象都进入信号态,还是只要有一个对象进入信号态就可以。

为了区别是否是创建控件的线程访问该控件,windows应用程序中每一个控件对象都有一个invokerequired属性,用来检查是否需要通过调用invoke方法完成其他线程对该控件的操作,如果该属性为true.说明是其他线程操作该控件,这时可以创建一个委托实例,然后调用控件对象的invoke方法,并传入需要的参数完成相应操作,否则可以直接对该控件对象进行操作,从而保证了其他线程安全操作本线程中的控件.。java线程之间的通信总是隐式进行 java并发模型—硬件视图 内存空间 共享对象 共享对象 共享对象 内存中的jvm 对象 程之间共享 线程1 线程2 处理器a 处理器b 处理器c 处理器d java并发模型—操作系统视图 jvm进程 hotspot vm中, java线程被 java线程 java线程 java线程 映射为本地操作系 统线程 linux kernel 操作系统内核 直接调度java 线程给可用的cpu处理器a 处理器b 处理器c 处理器d 编译器和处理器喜欢不择手段的冒险源代码 编译器优化 指令级并行 内存系统的 最终执行的 的重排序 的重排序 重排序 指令序列 编译器的 重排序 重排序 指令级并行的 处理器的 重排序 重排序 内存系统的 重排序 顺序一致性内存模型的原型结构 处理器a 处理器b 处理器c 处理器c a3 b2 d1 程序顺 a2 b1 c3 d2 序不变 a1 c2 每个内存 c1 单元一个 fifo队列内存单元 1 2 3 4 5 6 7 8 9 10 11 12 13 … … n顺序一致性内存模型的程序员视图 线程 线程 线程 线程 … 2 3 n 1 内存 顺序一致性内存模型的2 大特性 特性2 线程a 的程序顺序 操作的执行整体上无序,但两个线程 都只能看到这个执行顺序。1.主线程创建子线程并传入一个指向变量地址的指针作参数,由于线程启动须要花费一定的时间,所以在子线程根据这个指针访问并保存数据前,主线程应等待子线程保存完毕后才能改动该参数并启动下一个线程。

其余参数与KeWaitForSingleObject中的对应参数作用相同,而且大部分返回码也有相同的含义。

如果你指定了WaitAll,则返回值STATUS_SUCCESS表示等待的所有对象都进入了信号态。如果你指定了WaitAny,则返回值在数值上等于进入信号态的对象在objects数组中的索引。如果碰巧有多个对象进入了信号态,则该值仅代表其中的一个,可能是第一个也可能是其它。你可以认为该值等于STATUS_WAIT_0加上数组索引。你可以先用NT_SUCCESS测试返回码,然后再从其中提取数组索引:

NTSTATUS status = KeWaitForMultipleObjects(...);
if (NT_SUCCESS(status))
{
  ULONG iSignalled = (ULONG) status - (ULONG) STATUS_WAIT_0;
  ...
}

waitforsingleobject函数用来检测 hhandle事件的信号状态,当函数的执行时间超过dwmilliseconds就返回,但如果参数dwmilliseconds为infinite时 函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到waitforsingleobject有返回直才执行后面的代码。 不过对于自动重置事件不必执行resetevent,因为系统会在waitforsingleobject或者waitformultipleobjects返回前,自动将事件对象置为无信号态。 i++) { //等待互斥量,如果互斥量处于信号态,该函数返回,同时 //将g_hmutex变为无信号态 waitforsingleobject(g_hmutex,infinite)。

内核事件

表4-2列出了用于处理内核事件的服务函数。为了初始化一个事件对象,我们首先应该为其分配非分页存储,然后调用KeInitializeEvent:

ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KeInitializeEvent(event, EventType, initialstate);

event是事件对象的地址。EventType是一个枚举值,可以为NotificationEvent或SynchronizationEvent。通知事件(notification event)有这样的特性,当它进入信号态后,它将一直处于信号态直到你明确地把它重置为非信号态。此外,当通知事件进入信号态后,所有在该事件上等待的线程都被释放。这与用户模式中的手动重置事件相似。而对于同步事件(synchronization event),只要有一个线程被释放,该事件就被重置为非信号态。这又与用户模式中的自动重置事件相同。而KeWaitXxx函数在同步事件对象上执行的附加动作就是把它重置为非信号态。最后的参数initialstate是布尔量,为TRUE表示事件的初始状态为信号态,为FALSE表示事件的初始状态为非信号态。

表4-2. 用于内核事件对象的服务函数

服务函数描述

KeClearEvent

把事件设置为非信号态,不报告以前的状态

KeInitializeEvent

初始化事件对象

KeReadStateEvent

取事件的当前状态

KeResetEvent

把事件设置为非信号态,返回以前的状态

KeSetEvent

把事件设置为信号态,返回以前的状态

注意 在这些关于同步原语的段中,我还要再谈论一下DDK文档中对IRQL的使用限定。在当前发行的Windows 2000中,DDK有时比OS实际要求的有更多的限制。例如,KeClearEvent可以在任何IRQL上调用,但DDK却要求调用者必须在低于或等于DISPATCH_LEVEL级上调用。KeInitializeEvent也可以在任何IRQL上调用,但DDK要求仅在PASSIVE_LEVEL级上调用该函数。然而,你应该尊重DDK中的描述,也许某一天Microsoft会利用文档中的这些限制。

调用KeSetEvent函数可以把事件置为信号态:

ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
LONG wassignalled = KeSetEvent(event, boost, wait);

在上面代码中,ASSERT语句强制你必须在低于或等于DISPATCH_LEVEL级上调用该函数。event参数指向一个事件对象,boost值用于提升等待线程的优先级。wait参数的解释见文字框“KeSetEvent的第三个参数”,WDM驱动程序几乎从不把wait参数指定为TRUE。如果该事件已经处于信号态,则该函数返回非0值。如果该事件处于非信号态,则该函数返回0。

多任务调度器需要人为地提升等待I/O操作或同步对象的线程的优先级,以避免饿死长时间等待的线程。这是因为被阻塞的线程往往是放弃自己的时间片并且不再要求获得CPU,但只要这些线程获得了比其它线程更高的优先级,或者其它同一优先级的线程用完了自己的时间片,它们就可以恢复执行。注意,正处于自己时间片中的线程不能被阻塞。

用于提升阻塞线程优先级的boost值不太好选择。一个较好的笨方法是指定IO_NO_INCREMENT值,当然,如果你有更好的值,可以不用这个值。如果事件唤醒的是一个处理时间敏感数据流的线程(如声卡驱动程序),那么应该使用适合那种设备的boost值(如IO_SOUND_INCREMENT)。重要的是,不要为一个愚蠢的理由去提高等待者的优先级。例如,如果你要同步处理一个IRP_MJ_PNP请求,那么在你要停下来等待低级驱动程序处理完该IRP时,你的完成例程应调用KeSetEvent。由于PnP请求对于处理器没有特殊要求并且也不经常发生,所以即使是声卡驱动程序也也应该把boost参数指定为IO_NO_INCREMENT。

KeSetEvent的第三个参数

wait参数的目的是允许在内部快速地把控制从一个线程传递到另一个线程。除了设备驱动程序之外,大部分系统部件都可以创建双事件对象。例如,客户线程和服务器线程使用双事件对象来界定它们的通信。当服务器线程需要唤醒对应的客户线程时,它首先调用KeSetEvent函数,并指定wait参数为TRUE,然后立即调用KeWaitXxx函数使自己进入睡眠状态。由于这两个操作都以原子方式完成,所以在控制交接时没有其它线程被唤醒。

DDK总是稍稍地描述一些内部细节,但我发现有些描述另人迷惑。我将以另一种方式解释这些内部细节,看过这些细节后你就会明白为什么我们总指定这个参数为FALSE。在内部,内核使用一个“同步锁(dispatcher database lock)”来保护线程的阻塞、唤醒,和调度操作。KeSetEvent函数需要获取这个锁,KeWaitXxx函数也是这样。如果你把这个参数指定为TRUE,则KeSetEvent函数将设置一个标志以便KeWaitXxx函数知道你使用了TRUE参数,然后它返回,并且不释放这个锁。当你后来(应该立即调用,因为你此时正运行在一个比任何硬件设备都高的IRQL上,并且你占有着一个被极其频繁争夺的自旋锁)调用KeWaitXxx函数时,它不必再获取这个锁。产生的效果就是你唤醒了等待的线程并同时把自己置入睡眠状态,而不给其它线程任何运行的机会。

你应该明白,以wait参数为TRUE调用KeSetEvent的函数必须存在于非分页内存中,因为它在某段时间内执行在提升的IRQL上。很难想象一个普通设备驱动程序会需要使用这种机制,因为驱动程序决不会比内核更了解线程的调度。底线是:对该参数总使用FALSE。实际上,Microsoft暴露该参数给我们的原因仍不十分清楚。

调用KeReadStateEvent函数(在任何IRQL上)可以测试事件的当前状态:

LONG signalled = KeReadStateEvent(event);

返回值不为0代表事件处于信号态,为0代表事件处于非信号态。

下面要介绍一种方式与上面方式的不同,注意两者之间的差异:事件函数后的匿名函数内并没有其他的函数的调用,该this指向是指向事件对象的,在事件触发后的匿名函数中的this,因为该匿名函数是由事件对象obtn触发的,所以该this指向是指向obtn的,注意与上面的区别,上面的解决方式其实是利用词法作用域的手段来解决,并没有改变this的指向,是绕开了全局变量的指向问题,是将全局的this更改为局部的事件所指对象给替代了。java的线索支持也包括一组同步原语。上面语法格式中,@synchronized后面括号里的obj就是同步监视器.上面代码的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定.。


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-112548-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...