In multi thread application how can I redirect stderr & stdout in separate file as per thread?
I have multi thread application in which I'm creatin开发者_如何学Pythong a thread like this:
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]);
}
}
Now in the thread function, I want to redirect stderr
& stdout
in one separate file as per thread. Something like a thread log file.
How can I do so?
Edit:
If thread specific prints can be displayed on different terminal..? I mean if there are 2 threads then it opens 2 terminals & prints each threads data on different terminals.
If you really must do this...
First you need to create 2 pthread_key_t
s, 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.
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
.
stdout
and stderr
are unique streams, by definition. Imagine, how would shell redirect your streams if there were multiple stdout
s? 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.
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.
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.
精彩评论