0

Using pthreads, I created a thread that does audio recording through shell:

void *thread_function(void *arg) {

system("arecord data.wav");

}

However, when I call pthread_cancel(&thread_ID); to terminate the thread, the audio recorder still works on its own (Until I terminate the whole C program of course).

How do I stop a pthread that does a system call? Thanks in advance!

Ahmed Farid
  • 127
  • 1
  • 11

3 Answers3

2

Your thread start function should do the following:

pid_t pid;
int status;
posix_spawnp(&pid, "arecord", 0, 0, (char *[]){"arecord", "data.wav", 0}, environ);
pthread_cleanup_push(cleanup, &pid);
while (waitpid(pid, &status, 0)<0 && errno==EINTR);
pthread_cleanup_pop(0);

With a cleanup function like:

static void cleanup(void *p)
{
    pid_t pid = *(pid_t *)p;
    kill(pid, SIGTERM);
    while (waitpid(pid, &status, 0)<0 && errno==EINTR);
}

Then cancelling the thread with pthread_cancel will kill the child process.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
1
system("arecord data.wav");

It will make a separate process (not a thread in your program) in your system, and terminating that thread will not affect that process. You should kill that process by another system call.

However making the process with spawn* functions in non-waiting mode is a bit better than your way and in this case and you don't need an extra thread.

spawnl(P_NOWAIT, "arecord data.wav", .... );

But, killing the created process is ugly.

masoud
  • 55,379
  • 16
  • 141
  • 208
  • Seems logical. So I'll have to instead make a `system("killall arecord");`? – Ahmed Farid Apr 19 '13 at 19:29
  • Ubuntu 12.04. Anyways, just tested the `killall` method and it worked for me. Seems I won't have to use pthreads after all. Thanks a lot for your help! – Ahmed Farid Apr 19 '13 at 19:39
  • False alarm: At first I tried the `killall` thing with the threads mechanism. Without it, the program is stuck in the system call. So in essence, threads are still necessary. – Ahmed Farid Apr 19 '13 at 19:48
  • This answer is not sound advice. The point of calling `system` from a new thread is that your program can continue running while `system` blocks. However, `system` has lots of underlying thread-safety issues that make its use a very bad idea. Using `fork` and `exec` or better yet `posix_spawn` would be better. If you want a pthread-style interface, you can wrap it in a thread that calls `posix_spawn` then immediately calls `waitpid`, and the thread can have a cancellation function that kills the child process so that `pthread_cancel` can be used on it. – R.. GitHub STOP HELPING ICE Apr 19 '13 at 19:55
  • @MM.: That's even worse. Then you have no pid for the child process and thus no way to determine when it's finished or to kill it early. – R.. GitHub STOP HELPING ICE Apr 19 '13 at 19:56
  • AFAIK `arecord` is stopped by killing the process (CTRL+Z). The output .wav is fine and not corrupted. So I'm not worried of killing it, unless there's something about `arecord`'s control abilities I don't know. – Ahmed Farid Apr 19 '13 at 21:13
0

You can use pthread_kill to send a signal to a specific thread. The problem with thread cancellation is that it will be delayed until the program reaches a cancellation point (see this answer).

If you do use pthread_kill then you can choose which signal to send. I think it should be possible to end the thread with a kill signal which would then also end the child process spawned with system, although I'm not certain about that.

Community
  • 1
  • 1
Gabriel Southern
  • 9,602
  • 12
  • 56
  • 95