C / Linux: использование синхронизации потоков - PullRequest
1 голос
/ 16 апреля 2020

Мне трудно понять синхронизацию потоков. Мне дана следующая функция потока:

void *thread_function(void *unused)
{
    long aux;

    for(int i = 0; i < 1000; i++){
        aux = count;
        aux++;
        usleep(random() % 10);
        count = aux;

    }

    return NULL;
}

count - глобальная переменная, инициализированная в 0. Если я запускаю эту функцию с N числом потоков (например, 4), count колеблется вокруг значение 1000.

Почему это происходит, и какое должно быть правильное значение count? Если я поставлю семафор, sem_wait перед для l oop и sem_post после для l oop, означает ли это, что мои потоки больше не работают параллельно? Куда мне положить sem_wait и sem_post, чтобы мои потоки были правильно синхронизированы?

1 Ответ

1 голос
/ 16 апреля 2020

Вы предполагаете, что операции являются атомами c. Теперь предположим, что это не так, как в реальных системах.

Будучи глобальной переменной, к count могут обращаться все потоки в системе. Это означает, что без синхронизации все потоки будут выполнять следующие операции недетерминированно c и с чередованием:

for(int i = 0; i < 1000; i++){
    aux = count;
    aux++;
    usleep(random() % 10);
    count = aux;

}

Подводя итог, на каждой итерации l oop каждый поток будет иметь копию значения счетчика в данный момент времени, увеличит эту копию (aux++), а затем счетчику будет присвоено локальное значение count = aux;.

Проблема 1: Значение count чтение каждым потоком может изменяться в разных потоках, поскольку потоки выполняются, потому что один поток может считывать значение, которое изменяется другим потоком (или несколькими) в момент времени сразу после (помните, что операции не являются атомами c и могут быть выполнены с чередованием).

Проблема 2: Значение, назначенное для count, не защищено никаким механизмом блокировки, что означает, что несколько потоков могут выполнять эту инструкцию с перемежением или даже одновременно (например, в многопроцессорной системе это возможно). Это означает, что один из выполняющихся потоков (который вы не знаете, что это) установит значение count в aux в count = aux.

Простой пример возможного сценария выполнения :

Например, предположим, три потока. Поток 1 читает значение count = 100 и выгружается. Поток 2 считывает значение 100 и выполняет в течение некоторого времени установку счетчика (скажем, 300), а затем он выгружается. Наконец, поток 3 читает значение 300 и выполняет несколько итераций l oop. Если поток 1 выполняется снова и устанавливает значение count = aux, после одной итерации l oop значение будет установлено равным 101. Смотрите проблему!

Необходима синхронизация, чтобы убедиться, что только один поток выполняет чтение, приращение и присваивание, фактически, чтобы операции вели себя так, как если бы они были атомами c.


Q: Если я поставлю семафор, sem_wait перед для l oop, и sem_post после для l oop, означает ли это, что мои потоки больше не работают параллельно?

A: Это означает, что каждый поток будет чередовать выполнение для l oop. Например, поток 1 выполнит, скажем, 100 итераций для l oop, поток 2 выполнит 200 итераций и т. Д. c. Помните: планировщик контролирует выполнение каждого потока и, следовательно, количество итераций не контролируется пользователем. Ваш код синхронизирован, но не идеальным образом.


В: Куда мне поместить sem_wait и sem_post, чтобы мои потоки были правильно синхронизированы?

A : Вы должны использовать семафоры для наименьшего числа возможных операций, которые требуют синхронизации, чтобы извлечь максимальную выгоду из параллельного / параллельного выполнения кода. Например, используя семафоры, ваш код может быть:

for(int i = 0; i < 1000; i++){
    sem_wait(...);
        count++;
    sem_post(...);
}

Вам больше не нужно aux, так как семафор гарантирует, что только один поток увеличивает значение count.

Обратите внимание: поскольку вы используете потоки, вы также можете использовать мьютексы вместо семафоров.

Надеюсь, это прояснит ваши сомнения.

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