【问题标题】:Multiple requests single response synchronization多请求单响应同步
【发布时间】:2023-03-28 09:25:02
【问题描述】:

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

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

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

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

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

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) 部分。

【问题讨论】:

    标签: c synchronization mutex semaphore


    【解决方案1】:

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

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

    【讨论】:

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

    我终于想出了以下解决方案。将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 会被阻止超过应有的程度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-25
      • 2018-06-17
      相关资源
      最近更新 更多