This seems like it should be a well known problem, but I haven’t been able to find a good solution for it (neither from my brain nor the internet).
First, let’s take a very simple example:
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
So far so good. U (user) signals S (service), and waits for its response. Everything is good.
Now imagine if there were many users, requesting the same service. Now the nature of the service is such that the results vary in time (more precisely periodically). Therefore, if 10 users ask for the service more or less at the same time, the service can safely only run once.
The first thing that comes to mind is this:
Guy S:
while not finished
wait(request)
do stuff
trywait(request)
broadcast(response)
Guy U:
signal(request)
wait(response)
do stuff with results
The different here being that, first S trywaits on request effectively setting it to 0 and therefore if many people have signalled it, only one of the requests would go through. Of course the mutex has a cap of 1, so all the extra signals accumulate to 1, which would be removed by the trywait. Second change is that, S would broadcast the response so all the Us would be unblocked.
Looks good at first glance, but there is a problem with it. Imagine the following sequence of executions:
Guy S: Guy U1: Guy U2:
wait(request)
signal(request)
working
signal(request)
wait(response)
working
trywait(request)
broadcast(response)
wait(response)
working
(loop)
If you look closely, U2 is blocked unless someone sends a request again (god knows when in the future). Very bad.
Even with a single user, this can happen:
Guy S: Guy U:
wait(request)
signal(request)
working
trywait(request)
broadcast(response)
wait(response)
(loop)
Can anyone come up with a good idea, or direct me to a known algorithm?
Additional info:
Sonly periodically has new data to offer, but based on the application, the user may decide to get the data sporadically (through requests) rather than periodically. If the user requests too fast, I make him wait for the next period, so this it not an issue.- I have access to readers-writer locks, conditional variables, semaphores and mutexes. Readers-writer looked promising for the response lock, but it would still be unclear when all the users have passed their
wait(response)part.
I finally came up with the following solution. Having
requestandresponseas semaphores:I have to admit it is not perfect. Consider the following execution:
As you can see, in such a case, user 3 can “hijack” response of user 2. There would be no deadlock or anything, except user2 would stay blocked more than it deserves.