Передача структур в качестве аргументов при использовании pthread_create()

Я попытался передать структуру в качестве 4-го аргумента, используя pthread_create() примерно так:

pthread_create(&tid1, NULL, calca, &t); //t is the struct

Теперь всякий раз, когда я пытаюсь получить доступ к переменным в структуре - t.a, t.b или t.c, я продолжаю получать сообщение об ошибке - запрос члена в чем-то, что не является структурой или объединением.

Какой альтернативный метод я могу использовать для передачи структур в поток?


person skinderneath    schedule 14.05.2009    source источник


Ответы (8)


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

Попробуйте создать указатель на структуру в куче и передать этот указатель структуры в поток. Не забудьте удалить эту память где-нибудь (в треде, если вы никогда больше не будете ее использовать — или когда она вам больше не понадобится).

Кроме того, как упоминалось в Cyberconte, если вы собираетесь получать доступ к этим данным из разных потоков, вам необходимо заблокировать доступ к ним с помощью мьютекса или критической секции.

Редактировать 14 мая 2009 г., 12:19 EST: Кроме того, как уже упоминали другие люди, вы должны привести свой параметр к правильному типу.

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

void my_thread_func(void* arg){
    my_struct foo = *((my_struct*)(arg)); /* Cast the void* to our struct type */
    /* Access foo.a, foo.b, foo.c, etc. here */
}

Или, если вы передаете указатель на свою структуру:

void my_thread_func(void* arg){
    my_struct* foo = (my_struct*)arg; /* Cast the void* to our struct type */
    /* Access foo->a, foo->b, foo->c, etc. here */
}
person Lyndsey Ferguson    schedule 14.05.2009
comment
На самом деле, я создал поток в основной функции и создал структуру сразу после включения заголовочных файлов. Так что он должен быть доступен для всех функций (поправьте меня, если я ошибаюсь). - person skinderneath; 14.05.2009
comment
Ваше недавнее редактирование было самым полезным постом здесь до сих пор. Спасибо. - person skinderneath; 14.05.2009
comment
Спасибо, это спасло мой бекон. - person ; 14.03.2013
comment
Бекон стоит спасти. - person Lyndsey Ferguson; 25.02.2021

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

void my_thread_func(void* arg){
    my_struct foo = (my_struct)(*arg); /* Cast the void* to our struct type */
    /* Access foo.a, foo.b, foo.c, etc. here */
}
person Harper Shelby    schedule 14.05.2009
comment
Я сделал это, но теперь я получаю ошибку указателя разыменования 'void *'. - person skinderneath; 14.05.2009
comment
Харпер хотел написать: my_struct foo = *(my_struct *)arg; или my_struct *foo = (my_struct *)arg; - person Jonathan Leffler; 14.05.2009
comment
Использовал эту идею и опубликовал редактирование Линдси Фергюсон — 14 мая 2009 г., 12:19 по восточному поясному времени. - person skinderneath; 14.05.2009
comment
Да, приведение типов в стиле c не является моей сильной стороной, и прошло несколько лет с тех пор, как я использовал pthread_create. Я предпочитаю C++ и хорошую библиотеку потоков. - person Harper Shelby; 14.05.2009

  1. Создать семафор

  2. Создайте другую структуру, состоящую из указателя на вашу структуру и дескриптора семафора.

  3. Передайте указатель на эту новую структуру в pthread_create

  4. В родительском потоке, т. е. вызываемом pthread_create, ждите семафора

  5. В дочернем потоке скопируйте члены вашей структуры в локальные переменные или сохраните их в другом месте.

  6. В дочернем потоке подайте сигнал семафору

  7. В родительском потоке закройте семафор

person dmityugov    schedule 15.05.2009

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

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

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

person cyberconte    schedule 14.05.2009

Это сообщение об ошибке означает, что вы не разыменовываете указатель.

Ты говоришь "та" вместо "т->а"

[me@myhost ~]$ cat testitx.c
struct x {
        int a, b;
};

int main(int argc, char *argv[])
{
        struct x y, *z;

        z = &y;
        z.a = 10;
}
[me@myhost ~]$ cc -c testitx.c
testitx.c: In function `main':
testitx.c:10: error: request for member `a' in something not a structure or union
[me@myhost ~]$
person Community    schedule 14.05.2009
comment
Не помогает. Я использовал решение Harper Shelby, чтобы получить ошибку указателя разыменования 'void *'. - person skinderneath; 14.05.2009

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

Я объявляю и определяю функцию обработки потоков "обычным" способом:

void *ThreadFunction(sPARAMETERS *Params) {

  // do my threading stuff...

}

и когда я вызываю pthread_create, мне нужно использовать приведение:

pthread_create(&ThreadId,0,(void*(*)(void*)) &ThreadFunction,&Params);

Я почти никогда не забываю использовать & в параметрах, и компилятор позаботится обо всех ошибках, которые я допущу на другом конце. Отлично работает и для обратных вызовов.

person Marc Bernier    schedule 14.05.2009
comment
С технической точки зрения, это поведение undefined, хотя в большинстве компиляторов оно будет работать для обычных указателей на структуры. Не пытайтесь использовать указатели на функции-члены С++... - person bdonlan; 14.05.2009
comment
Я не понимаю, как это помогает решить мою проблему. Те приведения, которые вы использовали, слишком загадочны. - person skinderneath; 14.05.2009

my_struct foo = (my_struct)(*arg); is incoreect try my_struct *foo = (my_struct *)(arg);
И, в функции, вызывающей поток, убедитесь, что он статичен (чтобы память, на которую указывает, не терялась в тумане)

person user3512266    schedule 25.07.2014

Вот пример: это функция, которая создаст поток и передаст параметр структуры

pthread_create (& threads[i], NULL , PrintMessage ,(void *) &tab[i]);

И это функция потока:

 void *PrintMessage(void * arg)
{
struct param *mes_param ; mes_param = (struct param*) arg;
printf (" message from thread %d: %s\n", mes_param -> num_message ,
mes_param -> message );
pthread_exit(NULL);
}

Структура:

struct param {
int num_message ;
char* message ; };
struct param tab[MAX_THREADS];
person Abidi Mohamed    schedule 17.03.2021