c#Windows服务使用单个互斥锁控制多个线程

时间:2016-01-08 10:22:00

标签: c# .net multithreading service

我有一个可以创建多个线程的Windows服务;每个线程功能相同,但指向不同的服务器进行处理。但是,每个线程还从主服务器上的帐户表中读取一些数据。

我还有一个控制台应用程序,它将记录插入,更新和删除到所有线程都看到的帐户表中。

我需要做的是让控制台应用程序运行时所有服务线程都停止处理 - 控制台应用程序需要等到所有线程在开始执行任何操作之前暂停。当控制台应用程序完成时,线程需要继续处理。我想我可以使用以下逻辑使用两个互斥锁:

  1. 当服务启动时,它会获得对服务'的锁定。互斥 说它正在运行,然后创建并启动线程。

  2. 当控制台应用程序启动时,它会获得'帐户'互斥 说它正在运行。

  3. 控制台应用程序然后等待服务' mutex直到它     已经发布。

  4. 在每次处理过程中,服务的每个线程都会检查 '帐户'互斥锁,检查互斥锁是否被声明。如果 '帐户'声称mutex,该线程要求服务发布  '服务'互斥,然后等待帐户'互斥。

  5. 控制台应用程序正在进行处理。

  6. 控制台应用程序会释放'帐户'互斥,并关闭。

  7. 使用'帐户' mutex发布服务线程继续,和     要求服务获得“服务”服务。互斥。

  8. 我的问题是,我不知道如何让线程获得服务以获取或发布服务'互斥。

    我已尝试将静音方法中的mutex.WaitOne()/ mutex.ReleaseMutex()放入Service.cs中,但它们(显然)在线程上下文中执行(因此发布会抛出异常到期尝试释放线程不拥有的互斥锁 - 我想WaitOne还会导致错误,因为线程将声明互斥锁。)

    对此有何正确的解决方法?我可以在线程中执行某些操作来获取/释放互斥锁吗?我应该使用其他东西而不是互斥体吗?

2 个答案:

答案 0 :(得分:1)

我认为种族条件是任何方法的真正问题。但是,一种可能的,更简单的方法是在数据库中使用控制表。在其中有2个字段:一个线程计数器,在每个线程开始/结束后升级和降低,以及一个标志,指示控制台何时要运行 - 每个线程在运行和升级计数器之前首先检查。然后控制台将检查线程计数器是否达到零(通过彗星轮询或sql依赖)。

至少使用这种方法,您可以从外部观察线程正在做什么,并且根据您设置标志/计数器的时间,您可以减轻竞争条件。 (当然,如果您的服务或控制台应用程序崩溃,您将有脏数据 - 但清理控制表是没有意义的)

如果您确实需要实时处理,那么将两者结合到一个服务中是可行的方法......

答案 1 :(得分:0)

尽量避免通过互斥锁控制/同步工作管理器服务(Windows服务)和控制台应用程序。而是将控制台应用程序合并到Windows服务中。

执行此操作的一种方法是让Windows服务公开控制台应用程序可用于调用以前在控制台应用程序本身中的代码的wcf服务。 (我假设控制台应用程序允许人为干预)

现在,您需要在同一进程中完成所有需要同步的代码/线程。

从此处可以使用读写器锁进行同步,之前从控制台应用程序调用的代码将是编写器,在操作期间需要独占访问,服务线程将获取读取器访问权限(并且可以同时读取)。 / p>

如果控制台应用程序还需要执行读取访问并且有条件地仅执行更新,那么您可以获取可升级锁定。