Код, который он блокирует, защищает, его код между блокировкой и разблокировкой
pthread_mutex_lock(&mtx)
global_var = global_var + 10;
pthread_mutex_unlock(&mtx)
В этом простом случае вы защищаете приращения этой глобальной переменной, это необходимо, потому что процесс приращениячисло занимает три шага:
- Чтение текущего значения из ОЗУ
- Увеличение этого значения
- Запись этого значения обратно в ОЗУ
Давайте сосредоточимся на шагах 1 и 2. Поток МОЖЕТ (и будет уверен в этом) переключиться сразу после шага 1 (чтение), а другой поток прочитает то же значение , что и первыйодин, потому что у него никогда не было возможности обновиться обратно до оперативной памяти.Когда первый поток возобновляет работу (сразу после шага 1), он будет увеличивать это значение, прочитанное ранее, и записывать неверное конечное значение в ram, перезаписывая работу второго потока.
Другими словами:
[Thread 1] Reads the value 10
[Thread 2] Reads the value 10
[Thread 2] Increments it by 5 (value is now 15)
[Thread 2] Writes it back
[Thread 1] Increments it by 5 **(value is now 15)**
[Thread 1] Writes it back
Final value: 15
Окончательное значение должно быть 20, а не 15. Видите проблему?С мьютексом вы можете сериализовать доступ, расставляя вещи в правильном порядке, так что это становится
[Thread 1] Reads the value 10
[Thread 1] Increments it by 5 (value is now 15)
[Thread 1] Writes it back
[Thread 2] Reads the value 15
[Thread 2] Increments it by 5 (value is now 20)
[Thread 2] Writes it back
Final value: 20
Извините, если я запутался, но программирование потоков сначала сбивает с толку.Требуется время, чтобы подумать о многопоточности, но задержаться там!Это очень важная концепция, особенно сейчас, когда многоядерные процессоры являются стандартом де-факто.