Блокирует ли мьютекс доступ, пока он не разблокирован? - PullRequest
1 голос
/ 24 марта 2020

Предположим, это C код:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <unistd.h>

pthread_mutex_t lock;  
int a = 0;

void *myThreadFun(void *vargp) 
{ 
   pthread_mutex_lock(&lock); 
   a = 5;
   while (1) sleep(1);
   pthread_mutex_unlock(&lock);
   return NULL; 
} 

int main() 
{
   pthread_mutex_init(&lock, NULL);
   pthread_t thread_id; 
   pthread_create(&thread_id, NULL, myThreadFun, NULL);
   while (1){
    a = 6;
    sleep(1); 
    printf("%d\n", a);
   }       
   pthread_join(thread_id, NULL); 
}

Первый вывод 5, но все последующие отпечатки 6. Как так? myThreadFun создает блокировку и входит в бесконечное число l oop и никогда не разблокируется, так как же main перезаписать a?

Каким бы ни было положено значение между lock, будет защищено? то есть, если у меня есть больше переменных для защиты в myThreadFun Я просто помещаю их между одной и той же блокировкой?

Блокирует ли блокировка доступ, пока она не разблокирована, или блокирует доступ только до тех пор, пока не будут выполнены собственные операции чтения / записи? т.е. предотвратить частичное чтение и запись?

Ответы [ 2 ]

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

myThreadFun создает блокировку и входит в бесконечное число l oop и никогда не разблокирует

Правда, но для чего используется эта блокировка? Ничего. Никто не почитает замок, кроме нити. Программа main обращается к переменной без запроса какой-либо блокировки. Программа ничего не знает о том факте, что блокировка должна защищать переменную a. Это может быть использовано для чего угодно. Блокировка только предотвращает выполнение критических областей кода несколькими потоками одновременно, поскольку все они блокируются в начале критической области и разблокируются в конце.

Если вы хотите, чтобы это происходило правильно, вам придется правильно использовать блокировку и блокировать / освобождать ее для каждой части кода, которая взаимодействует с переменной. Примерно так (в main):

while (1) {
    pthread_mutex_lock(&lock);
    a = 6;
    sleep(1);
    printf("%d\n", a);
    pthread_mutex_unlock(&lock);
}

Блокировка доступа блокирует, пока она не разблокирована, или блокирует доступ только до тех пор, пока не будут выполнены собственные операции чтения / записи? т.е. чтобы предотвратить частичное чтение и запись?

Блокировка ничего не знает о чтении / записи, коде или переменных. Блокировка - это просто объект с двумя состояниями: заблокирован или разблокирован. Если его состояние разблокировано, то оно может быть заблокировано. Если его состояние заблокировано, то его нельзя заблокировать до тех пор, пока не произойдет разблокировка (а запрос блокировки заставляет поток ждать, пока блокировка не будет разблокирована).

Это все еще печатает 6. Я хочу, чтобы он печать 5. Я хочу заблокировать a в потоке, чтобы другие потоки не могли его коснуться.

Это другая проблема. Здесь необходимо убедиться, что запускаемый вами поток получает доступ к переменной a перед основным потоком . Если вы хотите достичь этого результата, вам нужно синхронизировать их. Другими словами, вы хотите, чтобы программа main ожидала, пока поток удерживает блокировку переменной.

Это может быть достигнуто различными способами. Вот рабочий пример использования семафора (для получения дополнительной информации посмотрите man sem_overview). ПРИМЕЧАНИЕ : хотя может показаться, что с помощью другого мьютекса вместо семафора может быть достигнуто следующее, но это не так. Основное различие между мьютексом и семафором заключается в том, что мьютекс может быть разблокирован только тем же потоком, который его заблокировал, тогда как семафор может свободно блокироваться или разблокироваться различными потоками.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

sem_t sem_main;
pthread_mutex_t lock_var_a;
int a = 0;

void *myThreadFun(void *vargp)
{
    pthread_mutex_lock(&lock_var_a);

    // Signal main that I acquired the lock.
    sem_post(&sem_main);

    a = 5;
    while (1) {
        printf("Thread: a = %d\n", a);
        sleep(1);
    }

    pthread_mutex_unlock(&lock_var_a);

    return NULL;
}

int main()
{
    sem_init(&sem_main, 0, 0);
    pthread_mutex_init(&lock_var_a, NULL);

    pthread_t thread_id;
    pthread_create(&thread_id, NULL, myThreadFun, NULL);

    // Wait for thread to acquire the lock.
    sem_wait(&sem_main);

    while (1){
        pthread_mutex_lock(&lock_var_a);

        // This code will never be executed.
        a = 6;
        printf("Main: a = %d\n", a);
        sleep(1);

        pthread_mutex_unlock(&lock_var_a);
    }

    pthread_join(thread_id, NULL);
}

В приведенном выше Пример программы main будет ожидать, пока поток не получит блокировку, прежде чем продолжить. В результате вы получите:

Thread: a = 5
Thread: a = 5
Thread: a = 5
...
0 голосов
/ 24 марта 2020

Если вы хотите, чтобы переменная была доступна только для определенного потока, объявите ее внутри функции потока:

void *myThreadFun(void *unused) 
{ 
   int a = 5;
   while (1) sleep(1);
   return 0;
}

Теперь main может совсем не понимаю, и блокировка не нужна.

...