9

我有一个在网络上运行的桌面应用程序,每个实例都连接到同一个数据库。

那么,在这种情况下,如何实现一个可在所有连接到同一数据库的正在运行的实例中工作的互斥锁?

换句话说,我不希望这两个以上的实例同时运行相同的功能。如果一个已经在运行该函数,则其他实例不应访问它。


PS:数据库事务不会解决,因为我不想互斥的功能不使用数据库。我提到数据库只是因为它可以用来在运行的实例之间交换信息。

PS2:该功能大约需要 30 分钟才能完成,所以如果第二个实例尝试运行相同的功能,我想显示一条很好的消息,它现在无法执行,因为计算机“X”已经在运行该功能.

PS3:该函数必须在客户端机器上处理,所以我不能使用存储过程。

4

6 回答 6

2

我认为您正在寻找数据库事务。事务会将您的更改与所有其他客户端隔离。

更新:您提到该函数当前不写入数据库。如果你想对这个函数进行互斥,必须有一些中心位置来存储当前的互斥持有者。数据库可以为此工作——只需添加一个包含当前持有者计算机名的新表。在开始您的功能之前检查该表。

我认为您的问题可能令人困惑。互斥锁应该是关于保护资源的。如果你的函数没有访问数据库,那么你在保护什么共享资源?

于 2009-11-05T18:48:18.913 回答
0

即使您的函数当前不使用数据库,您仍然可以使用特定表解决问题以同步此函数。具体情况取决于您的数据库以及它如何处理隔离级别和锁定。例如,使用 SQL Server,您可以将事务隔离设置为可重复读取,从锁定行中读取一个值并在事务中更新它。在您的功能完成之前不要提交事务。您还可以在大多数数据库的事务中使用显式表锁,这可能更简单。鉴于您已经在使用数据库,这可能是最简单的解决方案。

如果您出于某种原因不想依赖数据库,您可以编写一个简单的服务来接受来自客户端的 TCP 连接。每个客户端都会请求运行许可,并在完成后返回响应。服务器将能够确保一次只有一个客户端获得运行权限。只要您有正确的保持活动设置,死客户端最终会断开 TCP 连接并被检测到。

Xepoch 建议的消息队列解决方案也可以使用。您可以使用 MSMQ 或 Java 消息队列之类的东西,并拥有一条消息作为运行令牌。您的所有客户都会请求该消息,然后在完成后重新发布。如果客户在重新发布之前死亡,您将面临死锁的风险,因此您需要设计一些逻辑来检测这一点,并且它可能会变得复杂。

于 2009-11-05T19:16:47.117 回答
0

将代码放在事务中 - 在应用程序中,或者更好地 - 在存储过程中,然后调用存储过程。事务机制将隔离调用者之间的代码。

于 2009-11-05T18:50:07.920 回答
0

反过来考虑一个消息队列。如前所述,数据库应该在事务或对表的串行访问(ala MyISAM)中为您管理所有这些。

于 2009-11-05T18:52:21.400 回答
0

在过去,我做了以下事情:

  1. 创建一个表,基本上有两个字段,function_name 和 is_running
  2. 我不知道您使用的是什么 RDBMS,但大多数都有锁定单个记录以进行更新的方法。下面是一些基于 Oracle 的伪代码:

    开始翻译

    SELECT FOR UPDATE is_running FROM function_table WHERE function_name='foo';

    -- 在这里查看是否正在运行,如果没有,可以设置running为'true'

    UPDATE function_table set is_running='Y' where function_name='foo';

    提交翻译

现在我没有 Oracle PSQL 文档,但你明白了。'FOR UPDATE' 子句在读取之后锁定那里的记录直到提交,因此其他进程将阻塞该 SELECT 语句,直到当前进程提交。

于 2009-11-05T18:55:55.287 回答
0

如果您有 Java 堆栈,则可以使用Terracotta来实现此类功能。

于 2009-11-05T18:55:56.223 回答