views:

68

answers:

4

Is there any possibility to achieve different redirections for standard output like printf(3) for different POSIX thread? What about standard input?

I have lot of code based on standard input/output and I only can separate this code into different POSIX thread, not process. Linux operation system, C standard library. I know I can refactor code to replace printf() to fprintf() and further in this style. But in this case I need to provide some kind of context which old code doesn't have.

So doesn't anybody have better idea (look into code below)?

#include <pthread.h>
#include <stdio.h>

void* different_thread(void*)
{
    // Something to redirect standard output which doesn't affect main thread.
    // ...

    // printf() shall go to different stream.
    printf("subthread test\n");

    return NULL;
}

int main()
{
    pthread_t id;
    pthread_create(&id, NULL, different_thread, NULL);

    // In main thread things should be printed normally...
    printf("main thread test\n");

    pthread_join(id, NULL);
    return 0;
}
A: 

If you insist on using the standard I/O functions like "printf()" then the only way I can think of that this could be done is for the standard I/O library to support thread-specific I/O using thread-local data structures (similar to the way "errno" is a macro that calls a function that returns the thread-local error number). I don't know of any implementations of standard I/O that do this.

Steve Emmerson
Yes, I needed some way to do such thread-local standard I/O redirection. Original code was ported from VxWorks and this OS had native interface for things like this (and it was used by original authors). Now I need to either find mechanics I asked or extend all the code to support I/O context. I'm lucky, so I found relatively easy way.
Roman Nikitchenko
+3  A: 

You can do what you want if you create threads using clone, but POSIX.1 says that the threads must share open file discriptors.

There are several tricks you could try, but you really should just convert the calls to the FILE * argument accepting functions.

nategoose
Really nice point technically able to solve original task but after I had analyzed situation deeper I preferred to rework code as I plan to reuse it in future and I prefer not to introduce anything looking like fork() (yes, this was beyond original question).
Roman Nikitchenko
+1  A: 

On *nix systems, stdio layers over file descriptors, and file descriptors are global to a process. Thus, there is no way to do what you want without changing something. Your best bet is to rewrite code using fprintf(). Since this involves adding an argument to an arglist, I'm not even sure that you'd be able to use preprocessor trickery to achieve your goals without modifying the actual code.

Maybe you could clarify the reasons that you can't create new processes? The problem may be solvable from that angle.

Chris Cleeland
+1  A: 

If you have thread-local storage, you could do something like:

#undef printf
#define printf(fmt, ...) fprintf(my_threadlocal_stdout, fmt, __VA_ARGS__)

and likewise for all the other stdio functions you intend to use. Of course it would be better not to try redefining the same names, but instead perform search and replace on the source files to use alternate names.

BTW even without thread-local storage extensions to the compiler, you could use a function call that returns the right FILE * for the calling thread to use.

R..
Actually thread local storage was finally used for original case but I'm against global printf overloading because this can have unpredictable effects. I stayed on minimally reworked interface and internally hidden context based on thread local storage. This both provided compatible interface and good working solution. Limitation is one context per client thread which is acceptable for me.
Roman Nikitchenko