remzi-arpacidusseau/ostep-homework

Condition Variables

laushkeen opened this issue · 3 comments

I attempted to do homework, task 4 from the chapter "Condition Variables":

Let’s look at some timings. How long do you think the following execution, with one producer, three consumers, a single-entry
shared buffer, and each consumer pausing at point c3 for a second, will take? ./main-two-cvs-while -p 1 -c 3 -m 1 -C 0,0,0,1,0,0,0:0,0,0,1,0,0,0:0,0,0,1,0,0,0 -l 10 -v -t

When I launch main-one-cv-while.c using this code, the program seems to fall into the deadlock:

NF P0 C0 C1 C2
0 [--- ] p0
0 [
--- ] p1
1 [* 0 ] p4
1 [* 0 ] p5
1 [* 0 ] p6
1 [* 0 ] p0
1 [* 0 ] p1
1 [* 0 ] p2
1 [* 0 ] c0
1 [* 0 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c0
0 [
--- ] p3
1 [* 1 ] p4
1 [* 1 ] p5
1 [* 1 ] c0
1 [* 1 ] p6
1 [* 1 ] p0
1 [* 1 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c1
0 [
--- ] c2
0 [--- ] c1
0 [
--- ] c2
0 [--- ] p1
1 [
2 ] p4
1 [* 2 ] p5
1 [* 2 ] p6
1 [* 2 ] p0
1 [* 2 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c3
0 [--- ] c2
0 [
--- ] c0
0 [--- ] p1
1 [
3 ] p4
1 [* 3 ] p5
1 [* 3 ] p6
1 [* 3 ] p0
1 [* 3 ] c3
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c1
0 [
--- ] c2
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
4 ] p4
1 [* 4 ] p5
1 [* 4 ] p6
1 [* 4 ] p0
1 [* 4 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
5 ] p4
1 [* 5 ] p5
1 [* 5 ] p6
1 [* 5 ] p0
1 [* 5 ] c3
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c1
0 [
--- ] c2
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
6 ] p4
1 [* 6 ] p5
1 [* 6 ] p6
1 [* 6 ] p0
1 [* 6 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
7 ] p4
1 [* 7 ] p5
1 [* 7 ] p6
1 [* 7 ] p0
1 [* 7 ] c3
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c1
0 [
--- ] c2
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
8 ] p4
1 [* 8 ] p5
1 [* 8 ] p6
1 [* 8 ] p0
1 [* 8 ] c1
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c3
0 [
--- ] c2
0 [--- ] p1
1 [
9 ] p4
1 [* 9 ] p5
1 [* 9 ] p6
1 [* 9 ] c3
0 [--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c0
0 [--- ] c1
0 [
--- ] c2
0 [--- ] c3
0 [
--- ] c2
1 [EOS ] [main: added end-of-stream marker]
1 [EOS ] c1
0 [
--- ] c4
0 [
--- ] c5
0 [--- ] c6
0 [
--- ] c3
0 [--- ] c2
0 [
--- ] c3
0 [*--- ] c2

It stucks on the last operation and doesn't finish.

I can't reproduce this. Could you share more details? e.g., cut+paste how you compiled it, info about your platform, etc.

I'm compiling it on Windows 10 using MinGW 64 because it supports ptreads on Windows. Just use this command:

C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin>gcc "E:\HW-Threads-RealCV\main-one-cv-while.c" -o main-one-cv-while

Also, I had to change int to long long in the function

void *producer(void *arg) {
int id = (long long) arg;
// make sure each producer produces unique values
int base = id * loops;
int i;
for (i = 0; i < loops; i++) { p0;
Mutex_lock(&m); p1;
while (num_full == max) { p2;
Cond_wait(&cv, &m); p3;
}
do_fill(base + i); p4;
Cond_signal(&cv); p5;
Mutex_unlock(&m); p6;
}
return NULL;
}

void *consumer(void *arg) {
int id = (long long) arg;
int tmp = 0;
int consumed_count = 0;
while (tmp != END_OF_STREAM) { c0;
Mutex_lock(&m); c1;
while (num_full == 0) { c2;
Cond_wait(&cv, &m); c3;
}
tmp = do_get(); c4;
Cond_signal(&cv); c5;
Mutex_unlock(&m); c6;
consumed_count++;
}

// return consumer_count-1 because END_OF_STREAM does not count
return (void *) (long long) (consumed_count - 1);

}