Когда несколько потоков пытаются получить мьютекс одновременно, любой из них может получить его. Таким образом, если «неправильный» поток получает мьютекс, он должен каким-то образом уступить, чтобы правильный поток получил мьютекс. В коде OP sleep(0.2)
пытается сделать это. (Ожидание занято и не работает должным образом, поскольку unistd.h sleep()
принимает целое число секунд в качестве параметра.)
Лучшим вариантом будет использование мьютекса, условной переменной и индекса последовательности в качестве общей переменной. В псевдокоде каждый поток будет делать:
Function Thread(mynumber, mychar):
Lock mutex
Loop:
Wait on condition variable
If index >= limit:
Signal on condition variable
Unlock mutex
Return
Else
If (index % mynumber == 0):
Output mychar
Signal on condition variable
Else:
Broadcast on condition variable
End If
End Loop
End Function
Способ передачи более одной переменной в функцию потока очень похож на способ передачи символа. Вместо символа вы просто используете структуру. Например:
struct work {
int mynumber; /* Thread number: 0, 1, 2 */
int mychar; /* Character to output: '1', '2', '3' */
};
Вы можете объявить struct work w[3];
как глобальную переменную или в main()
и инициализировать ее, например,
struct work w[3];
w[0].mynumber = 0; w[0].mychar = '1';
w[1].mynumber = 1; w[1].mychar = '2';
w[2].mynumber = 2; w[2].mychar = '3';
и обозначьте их адрес как &(w[0])
(или, что эквивалентно, просто &w[0]
).
В функции потока вы можете использовать, например,
void *worker(void *payload)
{
struct work *const w = payload;
/* w->mynumber is the number (0, 1, 2) of this thread,
w->mychar is the char ('1', '2', '3') to output */
Обратите внимание, что pthread_cond_signal()
пробуждает один поток, уже ожидающий переменную условия, и pthread_cond_broadcast()
пробуждает все потоки, уже ожидающие переменную условия.
В обычном случае мы просыпаемся только одним потоком, чтобы попытаться избежать так называемой проблемы грома 1010 *. Это не настоящая проблема только с тремя потоками, но я подумал, что, возможно, это хорошая идея, чтобы представить эту концепцию здесь. Только если мы обнаружим, что текущий поток не является правильным, мы пробуждаем все потоки, ожидающие переменную условия.
Если бы мы только сигнализировали о условной переменной, то вполне возможно, что два неправильных потока будут просто чередоваться; вот почему нам действительно нужна эта передача.