微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

跨进程事件 – 可靠地释放所有服务员

我通过ManualResetEvent创build了一个跨进程事件。 当这个事件发生时,n个不同进程中的潜在的n个线程应该被解除阻塞并开始运行来获取新的数据。 问题是看起来ManualResetEvent.Set后跟一个立即重置不会导致所有等待线程唤醒。 那里的文档非常模糊

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx

当手动重置事件对象的状态发出信号时,它将保持发送状态,直到ResetEvent函数将其显式重置为非信号。 可以释放任何数量的等待线程,或者随后为指定事件对象开始等待操作的线程,同时可以释放对象的状态。

一个名为pulseEvent的方法,它似乎正是我所需要的,但不幸的是它也有缺陷。

在Linux上运行ASP.Net与标准的以微软为中心的解决scheme相比如何?

无法打开已被另一个我的应用程序打开的文件

什么是.NET平台文件扩展名?

如何刷新目录作为修复FileSystemWatcher的一种方法

如何删除俄语的本地化.NET Framework?

等待同步对象的线程可以通过内核模式APC暂时从等待状态中移除,然后在APC完成后返回到等待状态。 如果在线程从等待状态中移除期间发生对pulseEvent的调用,线程将不会被释放,因为pulseEvent只释放那些被调用时正在等待的线程。 因此,pulseEvent是不可靠的,不应该被新的应用程序使用。 相反,使用条件variables。

现在MSbuild议使用条件variables。

条件variables是同步原语,它使线程能够等待,直到发生特定情况。 条件variables是不能在进程间共享的用户模式对象。

在文档之后,我似乎已经不幸运行,可靠地做到了。 有没有一个简单的方法来完成相同的事情没有一个ManualResetEvent的限制,或者我需要为每个侦听器进程创build一个响应事件,以获得每个订阅调用者的ACK? 在这种情况下,我需要一个小的共享内存来注册订阅的进程的pid,但这似乎会带来一系列的问题。 当一个进程崩溃或不响应时会发生什么? ….

给一些上下文。 我有新的状态发布所有其他进程应该从共享内存位置读取。 当多次更新同时发生时,错过一个更新是可以的,但是过程必须至less读取最新的最新值。 我可以轮询超时,但似乎不是一个正确的解决scheme。

目前我正在下降

ChangeEvent = new EventWaitHandle(false,EventResetMode.ManualReset,counterName + "_Event"); ChangeEvent.Set(); Thread.Sleep(1); // increase odds to release all waiters ChangeEvent.Reset();

如何在.NET中执行应用程序内通信

重复(每日,每周,每月)的任务使用什么? 工作stream,Windows服务,别的?

如何操作windows程序

string结果成多行文本框

如果在3个否则可选的正则expression式expression式中至less有1个字符匹配,则需要“不匹配”

处理生产者必须唤醒所有消费者并且消费者数量在不断变化的情况下的一个通用选项是使用移动的围栏方法。 该选项也需要共享内存IPC区域。 这种方法有时会导致消费者在没有工作的情况下被唤醒,特别是当许多进程需要调度并且负载很高的时候,但是除了绝望的重载机器之外,它们总是会被唤醒。

创建几个手动重置事件,并让生产者维护一个计数器,以便设置下一个事件。 除了NextToFire事件之外,所有事件都保持设置。 消费者进程等待NextToFire事件。 当制片人希望唤醒所有消费者时,它重置Next + 1事件并设置当前事件。 所有消费者最终将被安排,然后等待新的NextToFire事件。 其效果是只有生产者使用ResetEvent,但是消费者总是知道下一个将要唤醒的事件。

所有用户初始化:(伪代码是C / C ++,而不是C#)

// Create Shared Memory and initialise NextToFire; pSharedMemory = MapMySharedMemory(); if (First to create memory) pSharedMemory->NextToFire = 0; HANDLE Array[4]; Array[0] = CreateEvent(NULL,1,"Event1"); Array[1] = CreateEvent(NULL,"Event2"); Array[2] = CreateEvent(NULL,"Event3"); Array[3] = CreateEvent(NULL,"Event4");

生产者唤醒所有

long CurrentNdx = pSharedMemory->NextToFire; long NextNdx = (CurrentNdx+1) & 3; // Reset next event so consumers block ResetEvent(Array[NextNdx]); // Flag to consumers new value long Actual = InterlockedIncrement(&pSharedMemory->NextToFire) & 3; // Next line needed if multiple producers active. // Not a perfect solution if (Actual != NextNdx) ResetEvent(Actual); // Now wake them all up SetEvent(CurrentNdx);

消费者等待逻辑

long CurrentNdx = (pSharedMemory->NextToFire) & 3; WaitForSingleObject(Array[CurrentNdx],Timeout);

从.NET 4.0开始,您可以使用MemoryMappedFile来同步进程内存。 在这种情况下,将计数器写入MemoryMappedFile并从工作进程中减量。 如果计数器等于零,则主进程允许重置事件。 这里是示例代码

主流程

//number of WorkerProcess int numWorkerProcess = 5; //Create MemroyMappedFile object and accessor. 4 means int size. MemoryMappedFile mmf = MemoryMappedFile.CreateNew("test_mmf",4); MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(); EventWaitHandle ChangeEvent = new EventWaitHandle(false,counterName + "_Event"); //write counter to MemoryMappedFile accessor.Write(0,numWorkerProcess); //..... ChangeEvent.Set(); //spin wait until all workerProcesses decreament counter SpinWait.SpinUntil(() => { int numLeft = accessor.ReadInt32(0); return (numLeft == 0); }); ChangeEvent.Reset();

WorkerProcess

//Create existed MemoryMappedfile object which created by main process. MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("test_mmf"); MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(); //This mutex object is used for decreament counter. Mutex mutex = new Mutex(false,"test_mutex"); EventWaitHandle ChangeEvent = new EventWaitHandle(false,"start_Event"); //.... ChangeEvent.WaitOne(); //some job... //decrement counter with mutex lock. mutex.WaitOne(); int count = accessor.ReadInt32(0); --count; accessor.Write(0,count); mutex.ReleaseMutex(); /////////////////////////////////////

如果环境小于.NET 4.0,则可以使用win32 API中的CreateFileMapping函数来实现。

你写道:“pulseEvent似乎正是我所需要的,但不幸的是它也有缺陷”。 pulseEvent的确是有缺陷的,但我不同意手动重置事件是有缺陷的。 这是非常可靠的。 有些情况下,您可以使用手动重置事件,并且有些情况下您不能使用它们。 这不是一劳永逸的。 还有很多其他工具,如自动重置事件,管道等

如果您需要定期通知一个线程,但不需要跨进程发送数据,则只需通知一个线程的最佳方法就是自动重置事件。 你只需要每个线程自己的事件。 所以,你有和线程一样多的事件。

如果您只需要将数据发送到进程,最好使用命名管道。 与自动重置事件不同,每个进程不需要自己的管道。 每个命名管道都有一个服务器和一个或多个客户端。 当有许多客户端时,操作系统为每个客户端自动创建相同命名管道的许多实例。 命名管道的所有实例共享相同的管道名称,但每个实例都有自己的缓冲区和句柄,并为客户端/服务器通信提供单独的管道。 使用实例可以使多个管道客户端同时使用同一个命名管道。 任何进程既可以作为一个管道的服务器,又可以作为另一个管道的客户端,反之亦然,使对等通信成为可能。

如果您将使用命名管道,那么在您的方案中根本不需要这些事件,并且无论进程发生什么情况,数据都将有保证的交付 – 每个进程可能会有很长的延迟(例如,通过交换),但数据将在没有您特别介入的情况下被最终传递。

所有线程(进程)的一个事件只有在通知只有一次的情况下才可以。 在这种情况下,您将需要手动重置事件,而不是自动重置事件。 例如,如果您需要通知您的应用程序很快就会退出,则可能会发出这种常见的手动重置事件。 但是,正如我之前写的,在你的情况下,命名管道是最好的选择。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐