2010-05-05 3 views
4

Ну, функция rand_r должна быть функцией, защищенной потоком. Однако, по его реализации, я не могу поверить, что он может не измениться другими потоками. Предположим, что два потока вызовут rand_r в одно и то же время с одним и тем же переменным семенем. Так начнется гонка чтения-записи. Код rand_r, реализованный glibc, приведен ниже. Кто-нибудь знает, почему rand_r называется потокобезопасным?Действительно ли 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; 
    } 

ответ

0

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

12

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

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

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

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

int globalSeed; 

//thread 1 
rand_r(&globalSeed); 

//thread 2 
rand_r(&globalSeed); 

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

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

17

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

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.

Смежные вопросы