C 多请求单响应同步

C 多请求单响应同步,c,synchronization,mutex,semaphore,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 re

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

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

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
这里的不同之处在于,首先,请求时
S
trywait
S有效地将其设置为0,因此,如果许多人发出了信号,则只有一个请求会通过。当然,互斥锁的上限为1,因此所有额外的信号累积为1,这将被
trywait
删除。第二个变化是,
S
广播
响应,因此所有
U
S都将被解锁

乍一看不错,但有个问题。设想以下执行顺序:

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)
    部分时,仍然不清楚

如果我理解问题描述,问题在于,有时候,服务实际上不需要做任何事情来计算新结果,而是可以“重用”以前的结果。(我知道在发出请求之前,您不会让服务做任何事情,因此我们不必担心它必须独立于请求进行更新。)如果是这样的话,您是否可以像这样修改原始服务:

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

如果我理解问题描述,问题在于,有时候,服务实际上不需要做任何事情来计算新结果,而只需要“重用”以前的结果。(我知道在发出请求之前,您不会让服务做任何事情,因此我们不必担心它必须独立于请求进行更新。)如果是这样的话,您是否可以像这样修改原始服务:

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

我终于想出了下面的解决办法。具有
请求
响应
作为信号量:

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被阻止的次数超过它应有的次数。

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

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会被阻止得太多。

如果需要重做内容,则
部分已经存在。为了简单起见,我把它去掉了。问题是,考虑两个用户:两个信号(请求)和服务唤醒,做一些事情和信号(响应)。有了这个信号,只有一个用户会醒来,另一个正在挨饿。我可以使用信号量而不是互斥量,这段代码(和我的原始代码一样)可以同时工作,但实际上“东西需要重做”不是很清楚(在我的应用程序中),我的目标是得到这样的东西:“如果在服务一个请求的中间,另一个来了,最后两个信号都发出信号,因为这两个结果都会被相同的结果所服务。虽然我说任务本质上是周期性的,但这并不完全正确。我有两种服务,其中一种是周期性的,我可以很容易地确定“是否需要重做东西”“。另一个是用户的扩展,具有我无法预测的任何功能。@Shahbaz:我假设信号量;我的错。(显然)你比我更了解上下文,但是如果另一个消费者没有完全完成他的请求(而不是刚刚完成请求),并且没有其他标准来确定结果,那么结果就不一样了。例如,如果服务记录了最后一个请求的处理时间,并且在某个窗口内传入的任何新请求都得到了相同的结果,那么实现起来就很容易了。你说的是真的,但让我再解释一下。这里的服务是一个线程,它生成共享内存的本地副本,该共享内存定期填充来自某些传感器的新数据。每个应用程序可能决定以不同的速率读取这些数据(例如,一个周期性,但另一个是零星的)。我有两个选择:每个请求只有在有东西需要更新时才会更新,否则返回。2) 块,直到有新数据。我选择了第二种方法,因为这样用户可以在循环中请求,并且只有在有新数据时才能安全地解除阻止。使用您的方法,不清楚“是第二个用户同时请求,所以应该返回”,还是“是同一个用户再次请求,并且必须阻止,直到新结果出现”如果需要重做东西,
部分已经存在。为了简单起见,我把它去掉了。问题是,考虑两个用户:两个信号(请求)和服务唤醒,做一些事情和信号(响应)。有了这个信号,只有一个用户会醒来,另一个正在挨饿。我可以使用信号量而不是互斥量,这段代码(和我的原始代码一样)可以同时工作,除了在现实中的“stuff nee”