Могу ли я вставить функцию в оператор pthread_mutex_lock и разблокировать операторы? - PullRequest
1 голос
/ 04 марта 2020

Давайте предположим, что я хочу установить в функцию atomi c инструкции.

Я объявил

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

в качестве глобальной переменной.

Вместо:

int main() {
     myFoo();
     ...
}

void myFoo() {
     pthread_mutex_lock(&mutex);
     myGlobal++;
     pthread_mutex_unlock(&mutex);
}

Могу ли я сделать:

int main() {
     pthread_mutex_lock(&mutex);
     myFoo();
     pthread_mutex_unlock(&mutex);
     ...
}

void myFoo() {
     myGlobal++;
}

Чтобы все инструкции в myFoo стали атомами c?

Ответы [ 2 ]

4 голосов
/ 04 марта 2020

В первом примере вы защищаете myGlobal, а во втором - myFoo. Ваш код работает так, как вы ожидаете (если вы вызываете его везде между блокировкой / разблокировкой), но вам нужно правильно использовать термины, иначе его значение будет неправильным.

Нет, это не будет atomi c , но доступ к myFoo будет синхронизирован, что означает, что никакой другой поток не может получить доступ к этому коду детали, когда его использует другой поток.

Atomi c термин операции обычно используется, показывая, что инструкция выполняется без прерывания (иногда считается свободной от блокировки). Например, C11 atomic_flag обеспечивает такую ​​функциональность. С другой стороны, мьютекс предназначен для создания взаимного исключения . Вы можете защитить часть своего кода от одновременного доступа из разных потоков. Эти 2 термина не похожи.

Примечание:

Только atomic_ тип, который гарантированно будет атомарным c и без блокировки atomic_flag является одновременно C и C ++. Другие, такие как atomic_int, могут быть реализованы с использованием метода синхронизации и не свободны от блокировки.

1 голос
/ 04 марта 2020

Вы используете термин atomi c не совсем правильно, но я думаю, вопрос больше в том, будут ли два фрагмента кода вести себя одинаково.

Если myFoo - это только вызывается между блокировкой / разблокировкой, ответ - да, они одинаковые.

Однако во втором случае вы потеряли защиту myFoo. Другой поток может вызвать myFoo без предварительного вызова блокировки, что может вызвать проблемы.

Итак, второй пример плохой, так как он открывает больше ошибок. Придерживайтесь первого, т.е. сохраняйте блокировку / разблокировку внутри функции .

Также обратите внимание:

Поскольку myGlobal является глобальной переменной, вы не можете быть уверены, что потоки не обращаются к нему напрямую. Есть несколько способов избежать этого. В приведенном ниже примере показана одна функция с переменной stati c. С помощью этой функции можно получить переменную stati c и, при желании, сделать приращение.

int myFoo(int doIncrement) 
{
     static int myStatic = 0;
     int result;
     pthread_mutex_lock(&mutex);
     if (doIncrement) myStatic++;
     result = myStatic;
     pthread_mutex_unlock(&mutex);
     return result;
}

Теперь переменная myStatic скрыта от всех потоков и доступна только через myFoo .

int x = myFoo(1);  // Increment and read
int y = myFoo(0);  // Read only
...