В многопоточном приложении, как я могу перенаправить stderr & stdout в отдельный файл в соответствии с потоком? - PullRequest
3 голосов
/ 09 сентября 2011

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

int main(int argc,char *argv[])
{
    pthread_t thread_id[argc-1];
    int i;
    struct parameter thread_data[argc-1];
    int status;
    for(i=0;i<argc-1;i++)
    {
      thread_data[i].ip_filename = argv[i+1];
      strcpy (thread_data[i].op_filename,argv[i+1]);
      strcat (thread_data[i].op_filename,".h264");
    }

    for(i=0;i<argc-1;i++)
    {
      pthread_create (&thread_id[i], NULL , &thread_function, &thread_data[i]);
    }      
}

Теперь в функции потока Я хочу перенаправить stderr & stdout в одномотдельный файл для потока. Что-то вроде файла журнала потока.

Как я могу это сделать?

Редактировать:

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

Ответы [ 5 ]

5 голосов
/ 09 сентября 2011

Если вы действительно должны сделать это ...

Сначала вам нужно создать 2 pthread_key_t с, один для stdout и один для stderr. Они могут быть созданы с использованием pthread_key_create, и они должны быть доступны из всех потоков. Давайте назовем их stdout_key и stderr_key.

Когда создается поток:

FILE *err = ..., *out = ...;
pthread_setspecific(stdout_key, out);
pthread_setspecific(stderr_key, err);

и затем в вашем заголовочном файле:

#define stdout (FILE*)pthread_getspecific(stdout_key)
#define stderr (FILE*)pthread_getspecific(stderr_key)
#define printf(...) fprintf(stdout, ##__VA_ARGS__)

тогда просто используйте:

fprintf(stderr, "hello\n");
fprintf(stdout, "hello\n");
printf("hello\n");

Я не рекомендую такой подход.

4 голосов
/ 09 сентября 2011

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

Вам нужно будет создать свои собственные файлы и изменить printf на fprintf.

1 голос
/ 09 сентября 2011

Вы должны будете отслеживать, что FILE* / fd использовать для каждой нити, использовать fprintf и т. Д. Другого пути нет.

Для нескольких терминалов вам необходимо открыть каждыйтерминал в вашей программе.Там нет никакого способа автоматически выяснить, какой открыть.Запустите /bin/tty в оболочке терминала, который вы хотите открыть, а затем откройте этот терминал в вашей программе.

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

1 голос
/ 09 сентября 2011

stdout и stderr являются уникальными потоками по определению. Представьте, как бы shell перенаправлял ваши потоки, если их было несколько stdout с? Вам нужно будет создать свои собственные выходные потоки / переменные файла и использовать их вместо этого. Есть ли проблема с этим?

Может оказаться полезным использовать хранилище, специфичное для потока .


Вы не можете заставить процесс выводить что-то на другой терминал. Процесс не знает о терминале, он просто выводит поток, и терминал поднимает его и отображает.

Однако вы можете направить вывод из одного из потоков в файл и запустить tail -f <filename> на другом терминале.

0 голосов
/ 07 мая 2012

Я использую fork() внутри потока для перенаправления stdout разветвленного процесса, пока "истинный" поток находится в waitpid(). Проблема в том, как передать файл, куда вы хотите перенаправить стандартный вывод. Я использую глобальный пул потоков, и поток находит себя через pthread_equal(pthread_self(),iterator), затем в структуре глобального пула потоков есть выходной файл, куда программа должна перенаправить стандартный вывод. В моем случае я создаю tmpnam() и записываю его в структуру потока, но вы можете использовать его по своему усмотрению.

Вот пример кода: (написано на лету)

pthread_t *t_cur=NULL;
int i,pid,newout;
char *outfile=NULL;

for(i=0;i<MAX_THREADS;i++)
  if(pthread_equal(pthread_self(),globals.tpool[i]->thread))
    break;
if(i==MAX_THREADS)
{
   printf("cannot find myself into global threads pool.\n");
   pthread_exit(&i);
 }
if(globals.tpool[i]->outfile == NULL) //  redirect stdout only if outfile is not set ( this is specfic for my purposes )
{
  outfile = globals.tpool[i]->outfile = malloc(L_tmpnam*sizeof(char));
  tmpnam(outfile);
}

if((pid = fork()) == 0)
{
   if(outfile!=NULL)
   {
     newout = open(outfile,O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
     dup2(newout,STDOUT_FILENO);
     close(newout);
   }
   /* your code here */
}
else
  waitpid(pid,NULL);
pthread_exit(&i);

Я действительно написал это на лету, я не тестировал этот код, поэтому постарайтесь исправить любые ошибки. Я не опубликовал свой настоящий код из-за звонков в мою собственную библиотеку. Здесь я не проверял возвращаемые значения из tmpnam(), fork(), open() и malloc(), что вы должны сделать.

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