How to properly exit a multi-threaded and multi-processes program? - c

I have to code a C program that runs several processes.
If one of these processes stops, I need them all other processes to exit properly (free everything + close every opened semaphores).
Processes can stop either because an error occured or because they died (a specific condition related to my program's purpose).
I only can use semaphores (no mutexes) and the pthread_create, pthread_join, ptthread_detach functions, no signals allowed !
What I did: I run 3 threads per process:
1 thread to execute the main purpose of my process (M),
1 thread to check for any other process' death (D),
1 thread to check for any other process' error (E),
Thread M just runs by default.
For threads D and E, I have a semaphore named /death (or /error) that is worth 0 when initialized. Whenever a process dies (or encounters an error), it posts this semaphore so it will enter in the respective thread, free everything, then posts it again to allow any other process to free again and quit and etc...
Here is an example for the death thread:
void *D_thread(void *args)
{
sem_wait(death_sem);
frees_everything();
sem_post(death_sem);
exit(0);
}
I have 2 issues:
While entering the D thread for example, my process will start freeing all its resources, while its M thread is still running and trying to access to these resources. Could this be a source of errors and should I then protect this with another semaphore ?
My processes will free one after the other, resulting potentially in a slow exit if many processes run together.
Do you think this is a good method or can you think of something else more efficient ? Again: I only can use semaphores (no mutexes) and the pthread_create, pthread_join, pthread_detach functions, no signals allowed !

Related

How many threads are placed in a process

How can I see the number of threads placed in a process in C ?
Actually, What I find out is whether newly-created process has one thread or no thread.(I am working in Linux)
The pthread_create() function starts a new thread in the calling process.So technically yes you can say there are two threads.The main thread,however remains the dominating one ,returning from main() causes the termination of all threads in the process.

Do you have to wait for a child thread to finish before you leave the thread that started it?

So lets say you create a thread in main (thread 1). This thread takes in some input from a file and creates multiple other threads (thread 2...etc) to process something. Do you have to exit the other threads (thread 2...) before exiting thread 1? If so how would I go about waiting for all the threads spawned by thread 1 to finish?
There are no parent/child relationships among threads. Threads are all peers. It makes no difference which thread started another thread, all the threads are equal parts of the process that contains them.
The special rule about calling pthread_exit from main only applies because returning from main terminates the process. There is no such concern with other threads -- they could only terminate the process by calling exit or a similar function.
Note that you should either join or detach each thread. You can detach all your threads and then you never have to worry about joining them -- they'll just run to completion and then clean themselves up.
No, you don't have to wait for the other threads to exit, in most situations. The whole point of threads is to start a sub-process of sorts that's largely independent of the thread that started it.
If you don't care how/when the thread will exit, though, you should usually detach the thread. Otherwise, it'll assume you care about its exit status, and it will sit there taking up resources -- even after it exits -- until some other thread joins it to retrieve the exit status.

How to handle a fork error for a multithreaded process?

I am working on a multithreaded process that forks to execute another process. Sometimes, the fork may error if the execution file does not exist. Since this process has multiple threads running prior to fork I have a couple questions:
Are threads copied over to the forked process.
What is the best practice to handling an error from fork with a multithreaded process. For example:
/* in a multithreaded process */
pid = fork();
if(pid == 0)
{
execlp(filename, filename, NULL);
fprintf(stderr, "filename doesn't exist");
/* what do i do here if there's multiple threads running
from the fork? */
exit(-1);
}
Well, the fork doesn't error if the executable file doesn't exist. The exec errors in that case. But, to your actual question, POSIX states that fork creates a new process with a single thread, a copy of the thread that called fork. See here for details:
A process shall be created with a single thread. If a multi-threaded process calls fork(), the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources.
Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.
So what you have is okay, if a little sparse :-)
A single thread will be running in the child and, if you cannot exec another program, log a message and exit.
And, in the rationale section, it explains why it was done that way:
There are two reasons why POSIX programmers call fork(). One reason is to create a new thread of control within the same program (which was originally only possible in POSIX by creating a new process); the other is to create a new process running a different program. In the latter case, the call to fork() is soon followed by a call to one of the exec functions.
The general problem with making fork() work in a multi-threaded world is what to do with all of the threads. There are two alternatives. One is to copy all of the threads into the new process. This causes the programmer or implementation to deal with threads that are suspended on system calls or that might be about to execute system calls that should not be executed in the new process. The other alternative is to copy only the thread that calls fork(). This creates the difficulty that the state of process-local resources is usually held in process memory. If a thread that is not calling fork() holds a resource, that resource is never released in the child process because the thread whose job it is to release the resource does not exist in the child process.
When a programmer is writing a multi-threaded program, the first described use of fork(), creating new threads in the same program, is provided by the pthread_create() function. The fork() function is thus used only to run new programs, and the effects of calling functions that require certain resources between the call to fork() and the call to an exec function are undefined.

Ctrl + C: does it kill threads too along with main process?

While running a thread program and repeatedly killing the main program using Ctrl + C, i see unexpected results in the program in second run. However, if i let the program run and voluntarily exit, there are no issues.
So, my doubt is, does Ctrl + C, kill threads also along with the main process?
Thanks in advance.
In multithreaded programming, signals are delivered to a single thread (usually chosen unpredictably among the threads that don't have that particular signal blocked). However, this does not mean that a signal whose default action is to kill the process only terminates one thread. In fact, there is no way to kill a single thread without killing the whole process.
As long as you leave SIGINT with its default action of terminating the process, it will do so as long as at least one thread leaves SIGINT unblocked. It doesn't matter which thread has it unblocked as long as at least one does, so library code creating threads behind the application's back should always block all signals before calling pthread_create and restore the signal mask in the calling thread afterwards.
Well, the only thing that Ctrl + C does is sending SIGINT to one thread in the process that is not masking the signal. Signals can be handled or ignored.
If the program does handle Ctrl+C, the usual behavior is self-termination, but once again, it could be used for anything else.
In your case, SIGINT is being received by one thread, which probably does kill itself, but does not kill the others.
Under Linux 2.6 using NPTL threads: I am assuming that the process uses the default signal handler, or calls exit() in it: Yes it does. The C library exit() call maps to the exit_group system call which exits all the threads immediately; the default signal handler calls this or something similar.
Under Linux 2.4 using Linuxthreads (or using 2.6 if your app still uses Linuxthreads for some weird reason): Not necessarily.
The Linuxthreads library implements threads using clone(), creating a new process which happens to share its address-space with the parent. This does not necessarily die when the parent dies. To fix this, there is a "master thread" which pthreads creates. This master thread does various things, one of them is to try to ensure that all the threads get killed when the process exits (for whatever reason).
It does not necessarily succeed
If it does succeed, it is not necessarily immediate, particularly if there are a large number of threads.
So if you're using Linuxthreads, possibly not.
The other threads might not exit immediately, or indeed at all.
However, no matter what thread library you use, forked child processes will continue (they might receive the signal if they are still in the same process-group, but can freely ignore it)

What makes a pthread defunct?

i'm working with a multi-threaded program (using pthreads) that currently create a background thread (PTHREAD_DETACHED) and then invokes pthread_exit(0). My problem is that the process is then listed as "defunct" and curiously do not seems to "really exists" in /proc (which defeats my debugging strategies)
I would like the following requirements to be met:
the program should run function A in a loop and function B once
given the PID of the program /proc/$pid/exe, /proc/$pid/maps and /proc/$pid/fd must be accessible (when the process is defunct, they are all empty or invalid links)
it must be possible to suspend/interrupt the program with CTRL+C and CTRL+Z as usual
edit: I hesitate changing the program's interface for having A in the "main" thread and B in a spawned thread (they are currently in the other way). Would it solve the problem ?
You can either suspend the execution of the main process waiting for a signal, or don't detach the thread (using the default PHTREAD_CRATE_JOINABLE) waiting for its termination with a pthread_join().
Is there a reason you can't do things the other way round: have the main thread run the loop, and do the one-off task in the background thread?
Not the most elegant design but maybe you could block the main thread before exiting with:
while(1) {
pause();
}
Then you can install a signal handler for SIGINT and SIGTERM that breaks the loop. The easiest way for that is: exit(0) :-).

Resources