views:

643

answers:

5

I am trying to channel data via pipes whenever a signal arrives from a thread to the main process.

Is this possible?
How can this be done?


The problem:

  1. A child thread reads data and puts it into a queue.
  2. Main application does its own stuff, however, when data is available on the queue, it should be notified by the thread, and start processing the data (main thread has access to the queue).

How should this scenario be implemented?

+1  A: 

It can be done, but it's rather unnecessary. Pipes are intended for inter-process communication. Threads share the same memory and can therefore communicate directly, as long as you use locking correctly.

Emil H
I would say pipes or a condition variable would be preferred over shared memory because you have to worry about all the problems with locks, shared memory, etc.
Doug T.
Yep, that might be the case. Depends on the application, though, so I thought I'd mention it.
Emil H
The main benefit to using pipes is that a single thread can wait and read from multiple pipes, instead of just a single queue signalled with a semaphore.
Greg Rogers
BTW, I only have one thread. I wonder if shared memory would be a better/easier solution.
Sasha are you comfortable with mutexes and locking? Have you had to deal with deadlocks or race-conditions in the past? Are you familiar with how difficult these can be to debug? I would suggest sticking with pipes as a simpler solution.
Doug T.
+3  A: 

Yes its possible through pipes.

Step one call pipe to get a pipe:

  #include <unistd.h>


  int main(...)
  {

    int fileDescriptors[2];
    pipe(fileDescriptors);

Step 2 pass the fileDescriptors[0] to the main process, and fileDescriptors[1] to the thread. In Main you wait for the pipe to be written to to by reading from fileDescriptors[0]

    ...
    char msg[100];
    read(fileDescriptors[0], msg, 100);  // block until pipe is read
  }

Step 3, from your thread write to fileDescritpors[1] when the signal occurs

 void signal_handler( int sig )
 {
     // Write to the file descriptor
     if (sig == SIGKILL)
     {
         const char* msg = "Hello Mama!";
         write(fileDescriptors[1], msg, strlen(msg));
     }
 }
Doug T.
A: 

If you're talking about pipe() rather than |, then yes. Pipes can generally just be treated as a file descriptor. You just need to open the pipe and cleanup the input in one thread, and the output in the other.

John Weldon
A: 

As others have said, this may be more trouble than it is worth.

However, if you insist.

Probably easiest just to open two pipes using popen and rw mode before spawning the thread. Choose one for main-->thread and the other for main<--thread and just go ahead.

Or you could open a total of four file descriptors after spawning, as if they were two different processes

dmckee
A: 

You could do that, apache has a similar "graceful restart" option. (see here). You would use something like:

#include <sys/types.h>
#include <signal.h>

kill(getppid(), SIGUSR1);

To send a signal to the parent. Others have the code above to spawn the file descriptors and catch it on the parent side.

However, I tend to avoid signals for scripted interprocess communication, instead using them only for "user sent" messages, like start/stop/restart/refresh. What you replace them with depends on your usecase: you could use a messaging variable, or if your main process is in a server loop, you could "select" on a pipe at the top of the loop to see if the child has sent a refresh message. There is probably a lot of others I'm missing.

Todd Gardner