这似乎应该是一个众所周知的问题,但我无法找到一个好的解决方案(无论是我的大脑还是互联网)。
首先,我们来看一个非常简单的例子:
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
删除。第二个变化是,S
会broadcast
响应,因此所有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)
部分。答案 0 :(得分:1)
如果我理解问题描述,问题在于,有时,服务实际上不需要做任何事情来计算新结果,但可以“重用”以前的结果。 (我发现在请求发出之前你没有服务做任何事情,所以我们不必担心它必须独立于请求更新内容。)如果是这样的话,你可以修改原始服务吗?像这样:
Service thread (Guy S):
while not finished
wait(request)
If stuff needs to be re done
do stuff
signal(response)
答案 1 :(得分:0)
我终于提出了以下解决方案。将request
和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会被阻止超过它应得的值之外,没有死锁或任何东西。