多个请求单响应同步

时间:2012-04-05 16:43:04

标签: c synchronization mutex semaphore

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

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

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

不同之处在于,首先要求S trywait有效地将其设置为0,因此如果有许多人发信号通知,则只有其中一个请求会通过。当然,互斥锁的上限为1,因此所有额外信号都会累积为1,这将被trywait删除。第二个变化是,Sbroadcast响应,因此所有U都会被解除阻止。

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

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仅定期提供新数据,但根据应用程序,用户可能会决定偶尔(通过请求)而不是定期获取数据。如果用户请求太快,我会让他等下一个句号,所以这不是问题。
  • 我可以访问读者 - 作家锁,条件变量,信号量和互斥量。读者 - 作者看起来很有希望获得响应锁定,但仍然不清楚所有用户何时通过他们的wait(response)部分。

2 个答案:

答案 0 :(得分:1)

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

Service thread (Guy S):
    while not finished
        wait(request)
        If stuff needs to be re done
            do stuff
        signal(response)

答案 1 :(得分: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的响应。除了user2会被阻止超过它应得的值之外,没有死锁或任何东西。