Почему замки работают? - PullRequest
4 голосов
/ 17 января 2009

Если блокировки обеспечивают доступ к заблокированным данным одновременно только одному потоку, то что контролирует доступ к функциям блокировки?

Я думал, что boost :: mutex :: scoped_lock должен быть в начале каждой из моих функций, чтобы локальные переменные не изменялись неожиданно другим потоком, это правильно? Что, если два потока пытаются получить блокировку в очень близкое время? Не будут ли локальные переменные блокировки, используемые внутри, повреждены другим потоком?

Мой вопрос не относится к бусту, но я, вероятно, буду его использовать, если вы не порекомендуете другой.

Ответы [ 4 ]

10 голосов
/ 17 января 2009

Вы правы, при реализации блокировок вам нужен какой-то способ гарантировать, что два процесса не получат блокировку одновременно. Чтобы сделать это, вам нужно использовать атомарную инструкцию - гарантированно выполненную без прерывания. Одной из таких инструкций является test-and-set , операция, которая получит состояние логической переменной, присвоит ей значение true и вернет ранее полученное состояние.

Это позволяет вам писать код, который постоянно проверяет, может ли он получить блокировку. Предположим, что x является общей переменной между потоками:

while(testandset(x));
// ...
// critical section
// this code can only be executed by once thread at a time
// ...
x = 0; // set x to 0, allow another process into critical section

Поскольку другие потоки постоянно проверяют блокировку, пока их не пропустят в критическую секцию, это очень неэффективный способ гарантировать взаимное исключение. Однако, используя эту простую концепцию, вы можете создавать более сложные управляющие структуры, такие как семафоры, которые намного более эффективны (поскольку процессы не зацикливаются, они спят)

10 голосов
/ 17 января 2009

Вам нужен только эксклюзивный доступ к общим данным. Если они не статичны или находятся в куче, локальные переменные внутри функций будут иметь разные экземпляры для разных потоков, и не нужно беспокоиться. Но общие данные (например, объекты, доступ к которым осуществляется с помощью указателей) должны быть заблокированы в первую очередь.

Что касается работы замков, они тщательно спроектированы для предотвращения состязаний и часто имеют поддержку на аппаратном уровне, чтобы гарантировать атомарность. То есть, есть некоторые конструкции машинного языка, которые гарантированно будут атомарными. Семафоры (и мьютексы) могут быть реализованы через них.

4 голосов
/ 17 января 2009

Самое простое объяснение состоит в том, что блокировки внизу основаны на аппаратной инструкции, которая гарантированно является атомарной и не может конфликтовать между потоками.

Обычные локальные переменные в функции уже относятся к отдельному потоку. Только статика, глобальные или другие данные могут быть одновременно доступны нескольким потокам, для которых необходимы блокировки, защищающие его.

0 голосов
/ 21 января 2009

Механизм, который управляет замком, контролирует доступ к нему.

Любой блокирующий примитив должен иметь возможность передавать изменения между процессорами, поэтому он обычно реализуется поверх операций шины, т. Е. Чтения и записи в память. Он также должен быть структурирован так, чтобы два потока пытались утверждать, что это не повредит его состояние. Это нелегко, но обычно можно полагать, что любая реализованная блокировка ОС не будет повреждена несколькими потоками.

...