Почему в pthread требуются специфичные для потока данные? - PullRequest
1 голос
/ 04 марта 2011

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

Просьба уточнить !!!.

BR Rj

Ответы [ 5 ]

3 голосов
/ 04 марта 2011

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

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

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

Скажем, у вас есть функция случайных чисел, в которой вы хотите поддерживать различную последовательность (следовательно, начальное число) для каждого потока. У вас есть два подхода.

Вы можете использовать что-то вроде kludgy:

int seed;
srand (&seed, time (NULL));
int r = rand_r (void *seed);

где семя должно быть создано вызывающим и передано в каждый раз.

Или вы можете использовать более приятный, соответствующий ISO:

srand (time (NULL));
int r = rand();

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

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

Теперь вы могли бы создать эту информацию в функции потока, но как функция rand узнает об ее адресе без его передачи. А что если rand называется 87 уровней стека вниз? Это очень много уровней для передачи указателя.

И даже если вы делаете что-то вроде:

void pthread_fn (void *unused) {
    int seed;
    rand_set_seed_location (&seed);
    :
}

и rand впоследствии используют это значение независимо от того, насколько глубоко оно находится в стеке, это все равно изменение кода по сравнению со стандартом. Это может работать, но также может писать операционную систему на языке COBOL. Это не делает его хорошей идеей: -)

0 голосов
/ 18 сентября 2011

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

Однако иногда вам нужно, чтобы TSD «замаскировал» дефект API.Хороший пример - «gmtime».Функция «gmtime» возвращает указатель на структуру, которая действительна до следующего вызова «gmtime».Но это сделало бы «gmtime» ужасно сложным для использования в многопоточной программе.Что если какая-то библиотека под названием 'gmtime', когда вы этого не ожидали, разрушает вашу структуру?Один простой обходной путь - сделать структуру возвращаемой для конкретного потока.(Долгосрочным решением, конечно, является создание более подходящего API, такого как 'gmtime_r'.)

Один случай, когда совершенно разумно использовать TSD в новых разработках, - это информация, которая не будетдоступ к часто, что загромождает API.Например, если обнаружена критическая ошибка, было бы неплохо записать определенную контекстную информацию из кода более высокого уровня (Какой клиент вы обслуживали? Какую команду они отправили?).В основном вы выбираете передачу этой контекстной информации от функции к функции (это даже не всегда возможно, если некоторые функции находятся вне вашего контроля) или ее сохранение в TSD.

0 голосов
/ 04 марта 2011

Наилучшим примером для данных, относящихся к потоку, является " errno ".При сбое вызова какой-либо функции из библиотеки c устанавливается errno , и вы можете проверить его, чтобы найти причину сбоя.Если нет данных, специфичных для потока, невозможно перенести эти функции в многопоточную среду, поскольку errno может быть установлен другими потоками, прежде чем вы проверите его.

0 голосов
/ 04 марта 2011

Да, стек - это один из способов выделения локального хранилища потока (включая дескрипторы выделения кучи, локальные для конкретного потока).

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