1

这似乎应该是一个众所周知的问题,但我无法找到一个好的解决方案(无论是从我的大脑还是互联网上)。

首先,我们举一个非常简单的例子:

mutex request  <-- init to 0
mutex response <-- init to 0

Service thread (Guy S):
    while not finished
        wait(request)
        do stuff
        signal(response)

Someone requestion service (Guy U):
    signal(request)
    wait(response)
    do stuff with results

到目前为止,一切都很好。U(用户)信号S(服务),并等待其响应。万事皆安。

现在想象一下,如果有很多用户请求相同的服务。现在服务的性质是结果随时间变化(更准确地说是周期性变化)。因此,如果有 10 个用户或多或少地同时请求该服务,则该服务只能安全地运行一次。

首先想到的是这个:

Guy S:
    while not finished
        wait(request)
        do stuff
        trywait(request)
        broadcast(response)

Guy U:
    signal(request)
    wait(response)
    do stuff with results

这里的不同之处在于,first S trywaits on request 有效地将其设置为 0,因此如果很多人已经发出信号,则只有一个请求会通过。当然,互斥体的上限为 1,因此所有额外的信号累积为 1,这将被trywait. 第二个变化是,响应是否会解除所有Ss的阻塞。broadcastU

乍一看还不错,但是有问题。想象以下执行顺序:

Guy S:              Guy U1:              Guy U2:
wait(request)
                    signal(request)
working
                                         signal(request)
                    wait(response)
working
trywait(request)
broadcast(response)
                                         wait(response)
                    working
(loop)

如果您仔细观察,U2除非有人再次发送请求(天知道将来何时),否则会被阻止。很坏。

即使只有一个用户,也可能发生这种情况:

Guy S:              Guy U:
wait(request)
                    signal(request)
working
trywait(request)
broadcast(response)
                    wait(response)
(loop)

任何人都可以想出一个好主意,或者指导我使用一个已知的算法吗?


附加信息:

  • S仅定期提供新数据,但根据应用程序,用户可能会决定偶尔(通过请求)而不是定期获取数据。如果用户请求太快,我让他等待下一个周期,所以这不是问题。
  • 我可以访问读写器锁、条件变量、信号量和互斥锁。Readers-writer 看起来很有希望使用响应锁,但仍不清楚所有用户何时都通过了他们的wait(response)部分。
4

2 回答 2

1

如果我理解问题描述,问题是,有时,服务实际上不需要做任何事情来计算新结果,而可以“重用”以前的结果。(我看到在提出请求之前您没有让服务做任何事情,所以我们不必担心它必须独立于请求更新内容。)如果是这种情况,您能否修改原始服务像这样:

Service thread (Guy S):
    while not finished
        wait(request)
        If stuff needs to be re done
            do stuff
        signal(response)
于 2012-04-05T19:42:15.047 回答
0

我终于想出了以下解决方案。具有requestresponse作为信号量:

Service thread (Guy S):
    while not finished
        wait(request)
        do stuff
        users_waiting = 1
        while (trywait(request))
            ++users_waiting
        for i = 0 to users_waiting
            signal(response)

Someone requestion service (Guy U):
    signal(request)
    wait(response)
    do stuff with results

我不得不承认它并不完美。考虑以下执行:

Guy S                Guy U1                Guy U2                Guy U3
Cycle 1:
wait(request)
                     signal(request)
                     wait(response)
do stuff
                                           signal(request)
trywait(request)
signal(response)
signal(response)
                     working                                            
                                                                 signal(request)
                                                                 wait(response)
                                                                 working
                                           wait(response)
Cycle 2:
wait(request)
do stuff
signal(response)
                                           working

如您所见,在这种情况下,用户 3 可以“劫持”用户 2 的响应。不会出现死锁或其他任何情况,除非用户 2 会被阻止超过应得的程度。

于 2012-04-06T12:47:27.877 回答