C: как работает pthread dataspecific? - PullRequest
       13

C: как работает pthread dataspecific?

4 голосов
/ 14 февраля 2009

Я не уверен в том, как работает pthread для конкретных данных: учитывая следующий код (найденный в Интернете), означает ли это, что я могу создать, например, 5 потоков в основном, вызывать func только в некоторых из них ( скажем, 2) эти потоки будут иметь какой-либо ключ данных (ptr = malloc (OBJECT_SIZE)), а другие потоки будут иметь тот же ключ, но со значением NULL?

static pthread_key_t key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void
make_key()
{
  (void) pthread_key_create(&key, NULL);
}

func()
{
  void *ptr;

  (void) pthread_once(&key_once, make_key);
  if ((ptr = pthread_getspecific(key)) == NULL) {
    ptr = malloc(OBJECT_SIZE);
    ...
    (void) pthread_setspecific(key, ptr);
  }
  ...
}

Будем благодарны за некоторые пояснения о том, как работает конкретная информация и как она может быть реализована в pthread (простым способом)!

Ответы [ 2 ]

6 голосов
/ 14 февраля 2009

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

Ключ является общим для всех потоков, так как он создается с pthread_once() в первый раз, когда это необходимо, но значение, данное этому ключу, отличается для каждого потока (если только оно не установлено в NULL). Имея значение void* для блока памяти, поток, которому требуются данные, специфичные для потока, может выделить его и сохранить адрес для последующего использования. И потоки, которые не вызывают подпрограмму, для которой нужны данные, относящиеся к конкретным потокам, никогда не тратят память, поскольку они никогда не выделяются для них.

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

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

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

Что касается реализации, из того, что я помню о потоках пользовательского режима DCE (которые, я думаю, предшествовали текущим потокам pthreads), каждый поток имел единую структуру, в которой хранились такие вещи, как указатели команд, указатели стека, содержимое регистров и т. Д. на. Было очень просто добавить один указатель на эту структуру, чтобы получить очень мощную функциональность с минимальными затратами. Указатель указывает на массив (связанный список в некоторых реализациях) пар ключ / указатель, поэтому у каждого потока может быть несколько ключей (например, один для strtok(), один для rand()).

1 голос
/ 14 февраля 2009

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

Реализация на самом деле не имеет большого значения (она может варьироваться в зависимости от ОС), если результаты одинаковы.

Вы можете думать об этом как о двухуровневой хэш-карте. Ключ указывает, к какой локальной переменной потока вы хотите обратиться, и второй уровень может выполнить поиск идентификатора потока, чтобы запросить значение для потока.

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