является ли rand_r реальным ориентированный на многопотоковое исполнение?

Ну, rand_r функция, как предполагается, ориентированная на многопотоковое исполнение функция. Однако его реализацией, я не могу полагать, что она могла заставить себя не измениться другими потоками. Предположим, что два потока вызовут rand_r в то же время с тем же переменным семенем. Таким образом, гонка чтения-записи произойдет. Код rand_r реализованный glibc упоминается ниже. Кто-либо знает, почему rand_r называют ориентированным на многопотоковое исполнение?

 int
    rand_r (unsigned int *seed)
    {
      unsigned int next = *seed;
      int result;

      next *= 1103515245;
      next += 12345;
      result = (unsigned int) (next / 65536) % 2048;

      next *= 1103515245;
      next += 12345;
      result <<= 10;
      result ^= (unsigned int) (next / 65536) % 1024;

      next *= 1103515245;
      next += 12345;
      result <<= 10;
      result ^= (unsigned int) (next / 65536) % 1024;

      *seed = next;

      return result;
    }
7
задан terry 5 May 2010 в 09:51
поделиться

3 ответа

Вы можете представить себе три уровня безопасности потоков, которые я обозначу здесь для удобства.

1) Совсем не потокобезопасный. Вызывать функцию одновременно из нескольких потоков небезопасно. Например, strtok .

2) Потокобезопасность по отношению к системе. Вызывать функцию одновременно из нескольких потоков безопасно при условии, что разные вызовы работают с разными данными. Например, rand_r , memcpy .

3) Потокобезопасность по отношению к данным. Вызывать функцию одновременно из нескольких потоков безопасно, даже работая с одними и теми же данными. Например, pthread_mutex_lock .

rand_r находится на уровне 2, и в контексте C (в частности, в спецификации POSIX) принято называть это «потокобезопасным».

В некоторых других языках, таких как Java, уровень 3 называется «потокобезопасным», а все остальное - «небезопасным для потоков». Так, например, java.util.Vector является «потокобезопасным», а java.util.ArrayList «небезопасным для потоков». Конечно, все методы java.util.ArrayList находятся на уровне 2. Таким образом, программист, пришедший с Java, может естественным образом вызвать rand_r и memcpy «не потокобезопасный. ".

В C соглашение иное, возможно, потому, что внутренне синхронизированные структуры данных с самого начала довольно редки. В контексте C вы можете спросить «являются ли файловые дескрипторы потокобезопасными?» И говорить об уровне 3, но когда спрашиваете «является ли эта функция потокобезопасной?» обычно означает уровень 2.

19
ответ дан 6 December 2019 в 05:42
поделиться

Потому что он изменяет начальное число, и оно передается.

0
ответ дан 6 December 2019 в 05:42
поделиться

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

Это отличается от большинства функций rand , которые хранят состояние (начальное значение) в глобальной переменной.

Предположим, что два потока одновременно вызовут rand_r с одним и тем же начальным значением переменной.

Я предполагаю, что вы имеете в виду что-то вроде этого

int globalSeed;

//thread 1
rand_r(&globalSeed);

//thread 2
rand_r(&globalSeed);

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

Это то же самое, что записать результат функции в глобальную переменную, к которой может получить доступ / изменить другой поток. Это не значит, что функция не безопасна для потоков, это означает, что ваш код не безопасен для потоков.

14
ответ дан 6 December 2019 в 05:42
поделиться