-   Programming (
-   -   c system function in child thread (

CoderMan 04-06-2009 08:38 PM

c system function in child thread
Hi. I wrote a curses app which used the "system" function to temporarily switch two an external program (so, as soon as the user quit the external program, he would be brought back to my application).

However, I recently split all the functionality of the app into two threads via the pthreads library. I needed to make the call to system from the second (child) thread (I don't know if it is technically considered a child thread...) But when I tried this odd things would happen: for example, if I tried to use system to open a bash prompt, the original app process would be turned into a stopped background job. (?)

I've been trying to accomplish the same thing with execl, but would appreciate any advice here. Execl, it seems, replaces the original process image. But if I use fork() with execl(), then somehow the input stream doesn't get completely passed to the new program as is the case with system.

grunt547 04-06-2009 09:27 PM

The system() call makes the whole calling process wait until the command completes, meaning both threads are blocked. If execl() isn't working for you, you could try forking a second process, calling system() from the child, then exiting the child as soon as the command completes. This would allow your original process to continue while the new one runs.

ta0kira 04-06-2009 10:55 PM

What's probably happening is the call to system creates a fork in the same process group as the original process. It sounds like the original process isn't in the foreground to start with, thereby causing the call to system to stop the entire process group until the session leader yields control of the terminal. There isn't much you can do about that while still having access to the terminal unless you fork, setpgid, and execvp instead of system.
Kevin Barry

On second thought, system might actually be calling setpgid and while bash steals foreground your console app is stuck in the background unable to perform terminal operations. Again, not much you can do about that; two things can't control the terminal at once.

CoderMan 04-08-2009 06:16 PM

I got this working. The issue was (as the previous posts mentioned) that the terminal can only have one process reading from the terminal at any given time.

According to the setpgid(2) man page (from the Linux programmer's manual):


A session can have a controlling terminal. At any time, one (and only one) of the process groups in
the session can be the foreground process group for the terminal; the remaining process groups are in
the background. If a signal is generated from the terminal (e.g., typing the interrupt key to gener‐
ate SIGINT), that signal is sent to the foreground process group. (See termios(3) for a description
of the characters that generate signals.) Only the foreground process group may read(2) from the
terminal; if a background process group tries to read(2) from the terminal, then the group is sent a
SIGTSTP signal, which suspends it. The tcgetpgrp(3) and tcsetpgrp(3) functions are used to get/set
the foreground process group of the controlling terminal.
In my application there are two threads. One thread is in charge of taking input from the user through getch(). The other thread is in charge of (among other things) calling system(). So system creates the new process like it is supposed to, but the first thread (and thus the original process) continues running and eventually calls getchar(). Consequently, the original app process receives the SIGTSTP signal from the terminal, and becomes a stopped background job.

So, I could continue to use system(). All I had to do, though, was to implementing locking (with a pthread mutex) to ensure that before the second thread calls system(), the first thread is blocked. Then I released the block on the first thread immediately after the system() function has returned.

(Side note: With my specific implementation of the locking, I dealt with a small issue related to the second thread having trouble being able to function correctly, since the first thread has the mutex locked over 99% of the time. I fixed this by adding in a few milliseconds of nanosleep to the first thread's loop, to ensure that the second thread has some time to get the mutex locked itself. I thought I'd mention that in case somebody else ran into the same problem.)

ta0kira 04-08-2009 11:55 PM

Yes, I've always been amazed at how a few 10ms pauses here and there can keep a program running smoothly. Out of curiosity, why do you use the terminal for two different purposes in the same program?
Kevin Barry

CoderMan 04-09-2009 11:40 PM


Originally Posted by ta0kira (Post 3503164)
Yes, I've always been amazed at how a few 10ms pauses here and there can keep a program running smoothly. Out of curiosity, why do you use the terminal for two different purposes in the same program?
Kevin Barry

I'm writing this curses-based program launcher, and I want each major component displayed on the screen running in its own thread, so I can easily have cool things like complex animations, clocks, dynamic menus, etc. One thread is dedicated just to input, and it messages the other threads.

Its been challenging learning the pthreads lib (and all the associated problems) but I think it has already payed off in making several parts of the programming easier to finish and a lot more fun to write.

wje_lq 04-10-2009 06:41 AM


Originally Posted by CoderMan (Post 3504277)
One thread is dedicated just to input

In the long run, you might find it useful to have one thread dedicated just to output as well. If you do, it will probably be useful to use pty's, one pair per program launch. pty's aren't trivial, but they're not rocket science.

For a smallish project with goals that you can clearly see from here, you might not want to do this. But if this project could eventually grow in complexity beyond what you see now, this might be worth it.

All times are GMT -5. The time now is 01:44 AM.