Является ли переменная локально объявленной в цикле, которая создает поток, безопасный для использования в вызываемом потоке, даже после следующей итерации? - PullRequest
0 голосов
/ 16 декабря 2009

У меня есть вопрос об области видимости переменных и управлении памятью на C. Я пишу программу, которая прослушивает соединение через сокет, а затем запускает новый поток для обработки этого клиента. Основной цикл while () может запускать множество отдельных потоков. У меня вопрос такой:

Если я не использую динамическое выделение памяти (нет malloc()) и вместо этого имею переменную, локально объявленную, как показано ниже, безопасно ли использовать эту переменную в вызываемом потоке, даже после следующей итерации цикла имеет место?

while(1)
{
    // Accept new socket connection here
    // ...

    pthread_t pt;
    struct mypthreadargs args;

    rc = pthread_create(&pt, NULL, handle_client, &args);
    // The handle_client() function makes extensive use of the 'args' variable
}

Что происходит с переменной args (и переменной pt) после создания потока? Потеряна ли память при повторном запуске цикла while (), или это безопасно использовать, как у меня?

Спасибо!

Ответы [ 4 ]

2 голосов
/ 16 декабря 2009

После каждой итерации вы теряете право владения pt и args. Доступ к ним - неопределенное поведение.

Чтобы обратиться к комментарию, вы можете определить массив обоих типов вне цикла или сделать их глобальными:

pthread_t pt[...];
struct mypthreadargs args[...];
while(1)
{
...
}

Конечно, вы должны убедиться, что вы не покинете эту область до того, как закончите свои потоки.

1 голос
/ 16 декабря 2009

Нет, вы не хотите этого делать.

Это может работать или не работать, в зависимости от того, как именно все это вызывается - реально, на большинстве архитектур, с большинством компиляторов, память, на которую указывает & args, останется действительной, но вы, скорее всего, в итоге получите несколько потоков, использующих одну и ту же структуру myptreadargs, которая, вероятно, вам не нужна (реальное поведение не определено, это только вероятный результат).

Вместо malloc( ) struct mypthreadargs.

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

0 голосов
/ 16 декабря 2009

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

0 голосов
/ 16 декабря 2009

Это невероятно небезопасно. Как только ваш поток будет создан и будет выполнен следующий цикл, в mpthreadargs, скорее всего, будут введены данные следующей итерации, а не данные, которые вы ожидали передать в поток.

Если вы не хотите использовать выделение кучи, вам нужно создать переменную в области видимости, которая переживет поток. Например, создайте массив объекта mpthreadargs в глобальной области видимости, размер которой будет соответствовать нужному количеству потоков. Если вы не знаете максимальный размер потоков, вам, скорее всего, придется использовать выделение кучи.

Почему вы все равно не пользуетесь malloc?

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