In multi thread application how can I redirect stderr & stdout in separate file as per thread?

前端 未结 5 1405
醉话见心
醉话见心 2020-12-16 08:14

I have multi thread application in which I\'m creating a thread like this:

int main(int argc,char *argv[])
{
    pthread_t thread_id[argc-1];
    int i;
             


        
相关标签:
5条回答
  • 2020-12-16 08:27

    stdout and stderr are unique streams, by definition. Imagine, how would shell redirect your streams if there were multiple stdouts? You would need to create your own output streams/file variables and use them instead. Is there a problem with that?

    You might find it useful to use thread-specific storage.


    You cannot make a process output something on a different terminal. The process doesn't know about terminal, it just outputs the stream, and the terminal picks it up and displays.

    What you can however do is to direct output from one of the streams into a file, and run tail -f <filename> in a different terminal.

    0 讨论(0)
  • 2020-12-16 08:31

    You will have to keep track of what FILE* / fd to use for each thread and use fprintf etc. There's no other way.

    For multiple terminals, you need to open each terminal in your program. There's no way to automatically figure out which one to open. Run /bin/tty in the shell of the terminal you want to open, and then open that terminal in your program.

    An alternative method would be to have a AF_UNIX socket listening for connections. Then you write a separate program which connects to that socket. You could run that program in the terminal where you wish output to appear.

    0 讨论(0)
  • 2020-12-16 08:32

    I don't think this is possible directly. stdin/stdout are global variables, shared between threads, and so are file descriptors.

    You'll have to create your own files, and change the printf into fprintf.

    0 讨论(0)
  • 2020-12-16 08:49

    I use a fork() inside the thread for redirect the stdout of the forked process while the "true" thread is in waitpid(). The problem is how to pass the file where you want to redirect stdout. I use a global thread pool, and the thread will find itself through pthread_equal(pthread_self(),iterator), then in the global thread pool structure there is the outfile where the program should redirect the stdout. In my case I create a tmpnam() and write it to the thread struct, but you can use it how you wish.

    Here is some example code: (written on the fly)

    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);
    

    I really wrote it on the fly, I haven't tested this code, so take care to fix any errors. I didn't post my real code because of calls to my own library. Here I didn't check the return values from tmpnam(), fork(), open() and malloc(), which you should do.

    0 讨论(0)
  • 2020-12-16 08:50

    If you really must do this...

    First you need to create 2 pthread_key_ts, one for stdout and one for stderr. These can be created using pthread_key_create, and they must be accessable from all threads. Let's call them stdout_key and stderr_key.

    When a thread is being created:

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

    and then in your header file:

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

    then just use:

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

    I don't recommend this approach though.

    0 讨论(0)
提交回复
热议问题