Передача нормальных данных в pthread void * - PullRequest
8 голосов
/ 04 мая 2011

Функции pthread принимают аргумент void *. Как можно отправить простую структуру, а не указатель?

Я хочу отправить структуру без указателя на одну функцию pthread.

Также я хочу отправить указатель на функцию void *, как это сделать? Можно ли отправить любой указатель на функцию void *?

Ответы [ 4 ]

8 голосов
/ 04 мая 2011

не возможно; Вы должны отправить указатель. Тем не менее, void * может указывать на что угодно. Если ваша переменная структуры называется foo, вы можете просто передать ее как (void *) &foo, а внутри функции вы можете преобразовать ее обратно, например, в. struct Foo с struct Foo * fooPtr = (struct Foo *) param; или struct Foo foo = *((struct Foo *) param);.

Редактировать: Как упоминалось в комментарии @forsvarir, foo не должно быть локальной переменной (если вызывающая функция не ожидает завершения потока). Смотрите сообщение @Gavin Lock.

7 голосов
/ 04 мая 2011

На основании ваших комментариев вам нужно сделать что-то вроде этого ...

В вашем основном коде:

void PassSomeStuff(struct TheStruct myStruct) {
    struct TheStruct *pStruct = malloc(sizeof(struct TheStruct));
    memcpy(pStruct, &myStruct, sizeof(struct TheStruct));

    /* Start the watchdog thread passing in the structure */
    pthread_create(/* other args */, &myWatchDogThreadFunc, pStruct); */
}

В вашей ветке сторожевого пса:

void *myWatchDogThreadFunc(void *pArgs) {
    struct TheStruct *pStruct = (struct TheStruct *)pArgs;

    /* use the struct */

    /* Pass Ownership to the navigation thread*/
    /* Start the navigation thread passing in the structure */
    pthread_create(/* other args */, &myNavigationThreadFunc, pStruct); 
}

В вашей ветке навигации:

void *myNavigationThreadFunc(void *pArgs) {
    struct TheStruct *pStruct = (struct TheStruct *)pArgs;
    /* use the struct */

    /* cleanup */
    free(pStruct);  /* or pass it to somebody else... */
}

Вы не можете просто сделать:

void PassSomeStuff(struct TheStruct myStruct) {
    pthread_create(/* other args */, &myStruct);
}

Потому что myStruct будет очищен ... когда PassSomeStuff вернется. Получая адрес (получая указатель на него), не копирует объект.

Примечание:

  • ЛЮБОЙ из ваших потоков может очистить структуру, вызывая free, если вы уверены, что ВСЕ потоки закончили с этим.
  • ВСЕ потоки (основной, сторожевой, навигация) ссылаются на один и тот же экземпляр структуры (поэтому, если они изменяют его содержимое, вам может понадобиться защитить его с помощью блокировки). Если это нежелательный эффект, вам нужно будет создавать (malloc) новую копию структуры на каждом шаге, чтобы у каждого потока была своя собственная копия значений.
3 голосов
/ 04 мая 2011

Как уже упоминалось, вы должны передать указатель. Думайте о void * как о нетипизированном указателе, поэтому вы должны привести его обратно к правильному типу внутри вашей функции потока. (см. ответ Аасмунда)

Как упоминает forsvarir, вы ДОЛЖНЫ убедиться, что указанная структура не уничтожена до того, как ее использует поток - самый безопасный способ сделать это - создать новую структуру в куче и передать ее адрес и принадлежность функции потока .

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

1 голос
/ 04 мая 2011

Это не полный ответ, а скорее альтернативное решение предупреждений, которые предлагали другие, чтобы убедиться, что структура все еще существует, когда ее получает новый поток. Конечно, вы можете использовать malloc для его получения и дать новому потоку ответственность за free его. Во многих отношениях это выглядит как самый простой и дешевый способ (синхронизация не требуется), но синхронизация на самом деле скрыта внутри malloc и free и может быть умеренно дорогой, тем более что большинство распределителей, ориентированных на потоки (ptmalloc и tcmalloc для пример) несут дополнительные расходы, когда поток, освобождающий память, отличается от потока, который ее выделил.

Другой подход, который вы можете использовать, - это установить барьер pthread внутри структуры инициализации и подождать его:

pthread_barrier_init(&init_struct.barrier, 0, 2);
pthread_create(&td, 0, start_func, &init_struct);
pthread_barrier_wait(&init_struct.barrier);

И пусть функция запуска потока также вызывает pthread_barrier_wait(arg->barrier); после копирования структуры в собственное автоматическое хранилище.

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