You need to manually copy the data to send it to two places, although this can be done a little more efficiently with Linux-specific tick and system calls (note tee syscall not tee command, http://blog.superpat.com/ 2010/07/08 / a-cup-of-tee-and-a-splice-of-cake / )
It sounds like you know how to do this, and you just hoped, but for others, the solution might be something like:
dup2 source stderr (usually terminal) to a new file descriptor to save it. Then make a pipe with a pipe (). dup2 end of pipe recording in fd 2. close the original end of fd recording. Now your stderr is a pipe. Run the thread or process. In this stream, you copy the data from the read end of your channel to the file and the original stderr that you saved. When a thread or process receives an EOF by reading a pipe, close it and exit.
The popen ("tee") solution is the same, except that it creates an additional shell process (and you need to correctly specify the file name passed to the shell if it has special characters ... be sure to check for strange filenames with large characters, spaces and quotation marks in them ...). If you use popen, I think you can also have a (cosmetic?) Problem that you cannot pclose () because your stderr will stop working, so you always leave the extra fd open and won't wait for the 4 () child.
If you used something like GLib, it has a g_spawn_async family of functions that you can use to create a tee command without a shell. Otherwise, you will need to manually use the fork / exec file to avoid the shell; you can execute the tee command, or you can develop, but NOT exec - just enter the child code after fork completes the stderr copy, do not rely on the tee command. Or you can use a thread instead of a process.
When using fork, you can find the source code in gspawn.c helpful; in any complex program, this is a pretty nightmare that FD_CLOEXEC is not standard for unix, for example, and it is easy to inherit child descriptors that cause problems. It is also quite annoying to avoid zombie processes and handle all errors and blah blah.
In any case, this is more code than you might expect, but between the tee source in coreutils and gspawn.c, you may have the most copy space available.