问题
So the description of the exercise:
You have this restaurant in which there are N points where you can ask for a portion of fries. Each point has M portions. There is 1 frycheff. When an order-point has 2 portions, it warns the cheff that it needs a refill. The cheff delivers the portions in order of FIFO.
We made this pseudo-code:
init {
Semafoor[] mutex;
Condition[] cond_point = new Condition[N];
int[] portions = new int[N];
ArrayList<int> waitline = new ArrayList<int>();
for(int i = 0; i < N; i++) {
mutex[i] = new Semafoor(1);
portions[i] = M;
}
}
point(int n) {
while(1) {
mutex[n].acquire();
if(portions[n] == 0) {
cond_point[n].wait(mutex[n]);
}
else if(portios[n] == 2) {
waitline.add(n);
}
portions[n]--;
mutex[n].release();
}
}
frycheff() {
int n;
while(1) {
if(!waitline.empty()) {
n = waitline.remove(0);
mutex[n].acquire();
portions[n] += M;
cond_point[n].signal();
mutex[n].release();
}
}
}
So we were wondering what happens when the wait()
statement blocks the point(int n)
signal. In our documentary it says they release the mutex in an atomic way, so there is no interference. But what about the other lines of code? (in the point(int n)
function)? Are the portions[n]
-- etc. - lines discarded? Will the signal()
statement recall to the point(int n)
function but in a reset manner so the function will run as new?
Thanks in advance!
回答1:
The man page of wait()
has further information about the behaviour. It talks about the pthread implementation specifically but this applies to every implementation in general.
https://linux.die.net/man/3/pthread_cond_wait
The most important parts are these:
pthread_cond_wait() functions shall block on a condition variable
wait()
is a blocking call. The thread is put to sleep by the scheduler. wait()
will return when a signal is received. There are no jumps. The execution will continue right after wait()
.
Note: Because of spurious wakeups it is possible that wait()
returns without good reason. You should therefore check if the condition really is met. Call wait()
in a loop:
// Condition: portions[n] > 0
while(portions[n] == 0)
cond_point[n].wait(mutex[n]);
They shall be called with mutex locked by the calling thread or undefined behavior results.
The mutex already needs to be locked when wait()
is called.
Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.
When wait()
returns it will have reacquired the lock. Anything else makes no sense and would lead to confusing situations, as you have seen.
So this is what will (could) happen:
--- point ------------------------- frycheff -------------------
mutex[n].acquire(); Serving other Points
else if(portios[n] == 2) Serving other Points
waitline.add(n); Serving other Points
portions[n]--; Serving other Points
mutex[n].release(); Serving other Points
...
mutex[n].acquire(); (BLOCKS) if(!waitline.empty())
mutex[n].acquire(); n = waitline.remove(0);
if(portions[n] == 0) mutex[n].acquire(); (BLOCKS)
cond_point[n].wait(mutex[n]); mutex[n].acquire();
Sleeping portions[n] += M;
Sleeping cond_point[n].signal();
wait() reaquires mutex[n] mutex[n].release();
portions[n]--; if(!waitline.empty())
mutex[n].release(); if(!waitline.empty())
Btw: You should probably use another mutex to synchronize the frycheff's calls to if(!waitline.empty())
and n = waitline.remove(0);
because write operations on an ArrayList are not threadsave.
来源:https://stackoverflow.com/questions/41330061/what-happens-to-mutex-acquirement-in-wait-signal-block