How to pthread_kill synchronously? - multithreading

I am starting a bunch of joinable worker threads and main() waits for them to completed with pthread_join(). However, a user may hit CTRL+C on the terminal before the worker threads have completed their task. My understanding is that any thread could get the signal so all my worker threads call pthread_sigmask() on start up and block SIGINT (the CTRL+C signal). This causes the signal to be copied to other threads and main(). This way I know that at least main() will get definitely the signal.
I have defined a signal handler function on main() so that main() gets the signal and can kill all the worker threads and free their resources from one place. The problem is that this happens asynchronously. I call pthread_kill() from main() and then try to free() resources the worker thread is using and it's still running because the signal is dispatched asynchronously.
If I call pthread_kill(SIGTERM, ...) from main() to kill the thread main() gets killed too and do_thread_cleanup(i) is never called:
int main () {
signal (SIGINT, signal_handler);
for (i = 0; i < num_thd; i++) {
pthread_create(thread_init, ...);
}
for (i = 0; i < num_thd; i++) {
pthread_join(...);
}
return 0;
}
void signal_handler(int signal) {
for (i = 0; i < num_thd; i++) {
pthread_kill(pthread_t, SIGINT);
pthread_join(pthread_t, ...);
do_thread_cleanup(i); // Calls functions like free() and close()
}
}
void thread_init() {
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
do_stuff_in_a_loop();
}
How can I send SIGKILL to a thread without main() receiving that signal and killing itself? Alternatively, how can I wait for the thread to exit?
Having read the other SO posts the talk about using pthread_cleanup_push() and pthread_cleanup_pop() but that doesn't allow me to check form one central place that all threads are killed and their resources released.

The short answer is that you can’t; but you can do something close.
Free(), malloc() and thus all paths leading to them are not signal safe; so you can’t call them from a signal handler. It is rare that these functions would notice the signal (re)entry, so unpredictable behaviour is the likely result.
A good pattern is to have the main thread notice signals have occurred, and perform the processing for them within it. You can do this, safely, by having the main thread employ a pthread_cond_t,pthread_mutex_t pair to watch a counter, and have the signal handler use the same pair to update the counter and notify the change.
Thus the main thread can treat signals as simple inputs to transition between states, such as Normal/SIGINT -> Quitting, Quitting/SIGALRM -> HardStop.
Free() is probably a bit heavy-handed, as it can cause your program to make sporadic memory references, which may be exploitable as an attack surface.

Related

Is it guaranteed that the kill() function will not return until the signal handler has done if a process kills itself?

Imagine the following program written in C:
void handler(int signo) {
write(STDOUT_FILENO, "handler\n", 8);
}
int main() {
signal(SIGUSR1, handler);
kill(getpid(), SIGUSR1);
write(STDOUT_FILENO, "after kill\n", 11);
}
If I run this program in Linux, is it possible the output is as follow:
after kill
handler
I tried many times, and the above result didn't appear.
If the SIGINT signal is delivered to the process after the puts("looping"); statement, then it will print the string "handler1" in the handle1 function. When the kill function returns, the output depends on when the SIGUSR1 signal will be delivered to the process. I think you can use the sigsuspend function to make sure it's what you want. By the way, before kill function returns, at least an unblocked signal is delivered to the process.
The following code outputs what you want and you need to block the SIGUSR1 signal first.
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void handler(int signo) {
write(STDOUT_FILENO, "handler\n", 8);
}
int main() {
sigset_t newmask, oldmask;
sigemptyset( &newmask );
sigaddset( &newmask, SIGUSR1 );
signal(SIGUSR1, handler);
// block the SIGUSR1 signal
sigprocmask ( SIG_BLOCK, &newmask, &oldmask );
kill(getpid(), SIGUSR1);
write(STDOUT_FILENO, "after kill\n", 11);
// reset the signal mask
sigprocmask ( SIG_SETMASK, &oldmask, NULL );
}
puts is not good inside signals handlers. Read signal(7), puts is not async-signal-safe. You should use write(2) inside a signal handler (not puts).
You have edited your question to use write instead of  puts
And if you insist in wrongly using puts you should at least call fflush. But both are wrong inside signal handlers.
(Don't forget that stdoutis buffered)
BTW, it might happen (notably in multi-threaded application, where the signal handler is not running in the same thread that kill(2)-s the signal) that the signal handler is invoked after returning of kill
I'm not sure that you are guaranteed that the signal handler of a single-threaded process is returning before kill, even if I believe that would happen on most Linux kernels. What you should be sure is that the signal handler would eventually be called (but you cannot be sure on when exactly). Also, a kernel is permitted to lose some signals (e.g. if an external thing or process is sending a lot of same signals). So called POSIX real-time signals are the exception, not the norm (see also this)
If you have an event loop (e.g. around poll(2)) and accept to have Linux-specific code
you could consider using signalfd(2) and polling it inside your event loop.

How to implement a re-usable thread barrier with std::atomic

I have N threads performing various task and these threads must be regularly synchronized with a thread barrier as illustrated below with 3 thread and 8 tasks. The || indicates the temporal barrier, all threads have to wait until the completion of 8 tasks before starting again.
Thread#1 |----task1--|---task6---|---wait-----||-taskB--| ...
Thread#2 |--task2--|---task5--|-------taskE---||----taskA--| ...
Thread#3 |-task3-|---task4--|-taskG--|--wait--||-taskC-|---taskD ...
I couldn’t find a workable solution, thought the little book of Semaphores http://greenteapress.com/semaphores/index.html was inspiring. I came up with a solution using std::atomic shown below which “seems” to be working using three std::atomic.
I am worried about my code breaking down on corner cases hence the quoted verb. So can you share advise on verification of such code? Do you have a simpler fool proof code available?
std::atomic<int> barrier1(0);
std::atomic<int> barrier2(0);
std::atomic<int> barrier3(0);
void my_thread()
{
while(1) {
// pop task from queue
...
// and execute task
switch(task.id()) {
case TaskID::Barrier:
barrier2.store(0);
barrier1++;
while (barrier1.load() != NUM_THREAD) {
std::this_thread::yield();
}
barrier3.store(0);
barrier2++;
while (barrier2.load() != NUM_THREAD) {
std::this_thread::yield();
}
barrier1.store(0);
barrier3++;
while (barrier3.load() != NUM_THREAD) {
std::this_thread::yield();
}
break;
case TaskID::Task1:
...
}
}
}
Boost offers a barrier implementation as an extension to the C++11 standard thread library. If using Boost is an option, you should look no further than that.
If you have to rely on standard library facilities, you can roll your own implementation based on std::mutex and std::condition_variable without too much of a hassle.
class Barrier {
int wait_count;
int const target_wait_count;
std::mutex mtx;
std::condition_variable cond_var;
Barrier(int threads_to_wait_for)
: wait_count(0), target_wait_count(threads_to_wait_for) {}
void wait() {
std::unique_lock<std::mutex> lk(mtx);
++wait_count;
if(wait_count != target_wait_count) {
// not all threads have arrived yet; go to sleep until they do
cond_var.wait(lk,
[this]() { return wait_count == target_wait_count; });
} else {
// we are the last thread to arrive; wake the others and go on
cond_var.notify_all();
}
// note that if you want to reuse the barrier, you will have to
// reset wait_count to 0 now before calling wait again
// if you do this, be aware that the reset must be synchronized with
// threads that are still stuck in the wait
}
};
This implementation has the advantage over your atomics-based solution that threads waiting in condition_variable::wait should get send to sleep by your operating system's scheduler, so you don't block CPU cores by having waiting threads spin on the barrier.
A few words on resetting the barrier: The simplest solution is to just have a separate reset() method and have the user ensure that reset and wait are never invoked concurrently. But in many use cases, this is not easy to achieve for the user.
For a self-resetting barrier, you have to consider races on the wait count: If the wait count is reset before the last thread returned from wait, some threads might get stuck in the barrier. A clever solution here is to not have the terminating condition depend on the wait count variable itself. Instead you introduce a second counter, that is only increased by the thread calling the notify. The other threads then observe that counter for changes to determine whether to exit the wait:
void wait() {
std::unique_lock<std::mutex> lk(mtx);
unsigned int const current_wait_cycle = m_inter_wait_count;
++wait_count;
if(wait_count != target_wait_count) {
// wait condition must not depend on wait_count
cond_var.wait(lk,
[this, current_wait_cycle]() {
return m_inter_wait_count != current_wait_cycle;
});
} else {
// increasing the second counter allows waiting threads to exit
++m_inter_wait_count;
cond_var.notify_all();
}
}
This solution is correct under the (very reasonable) assumption that all threads leave the wait before the inter_wait_count overflows.
With atomic variables, using three of them for a barrier is simply overkill that only serves to complicate the issue. You know the number of threads, so you can simply atomically increment a single counter every time a thread enters the barrier, and then spin until the counter becomes greater or equal to N. Something like this:
void barrier(int N) {
static std::atomic<unsigned int> gCounter = 0;
gCounter++;
while((int)(gCounter - N) < 0) std::this_thread::yield();
}
If you don't have more threads than CPU cores and a short expected waiting time, you might want to remove the call to std::this_thread::yield(). This call is likely to be really expensive (more than a microsecond, I'd wager, but I haven't measured it). Depending on the size of your tasks, this may be significant.
If you want to do repeated barriers, just increment the N as you go:
unsigned int lastBarrier = 0;
while(1) {
switch(task.id()) {
case TaskID::Barrier:
barrier(lastBarrier += processCount);
break;
}
}
I would like to point out that in the solution given by #ComicSansMS ,
wait_count should be reset to 0 before executing cond_var.notify_all();
This is because when the barrier is called a second time the if condition will always fail, if wait_count is not reset to 0.

SIGINT signal re-install in linux

I am writing a program dealing with Linux signals. To be more specific, I want to re-install signal SIGINT in child process, only to find that it doesn't work.
Here is a simpler version of my code:
void handler(int sig){
//do something
exit(0);
}
void handler2(int sig){
//do something
exit(0);
}
int main(){
signal(SIGINT, handler);
if ((pid = fork()) == 0) {
signal(SIGINT, handler2); // re-install signal SIGINT
// do something that takes some time
printf("In child process:\n");
execve("foo", argv, environ); // foo is a executable in local dir
exit(0);
}else{
int status;
waitpid(pid, &status, 0); // block itself waiting for child procee to exit
}
return 0;
}
When shell is printing "In child process:", I press ctrl+c. I find that function handler is executed without problem, but handler2 is never executed.
Could you help me with this bug in my code?
Update:
I want the child process to receive SIGINT signal during foo running process, is that possible?
It is not a bug - calling execve has replaced the running binary image. The function handler2() (and any other function of your binary) is no longer mapped in the program memory having been replaced by the image of "foo" and therefore all signal settings are replaced to a default.
If you wish the signal handler to be active during "foo" run, you have to:
make sure the handler function is mapped into the memory of foo
a signal handler is registered after "foo" starts.
One way to do this is to create a shared library that contains the signal handler and an init function that is defined as a constructor that registers said signal handler and force it into the "foo" memory by manipulating the environment under which you execve foo (the environ variable) to include
LD_PRELOAD=/path/to/shared_library.so
#gby's anwser has given comprehensive background knowlegde. I am here to give another solution without shared library.
Every time child process stops or terminates, parent process will receive SIGCHLD. You can handler this SIGCHLD signal to know if child process was terminated by SIGINT. In your handler:
pid_t pid = waitpid(pid_t pid,int * status,int options)
You can get status of child process through waitpid function.
if(WIFSIGNALED(status) && (pid == child_pid)){
if(WTERMSIG(status) == SIGINT){
// now you know your foo has received SIGINT.
// do whatever you like.
}
}

CoGetInterfaceAndReleaseStream let my thread hangs

UINT __stdcall CExternal::WorkThread( void * pParam)
{
HRESULT hr;
CTaskBase* pTask;
CComPtr<IHTMLDocument3> spDoc3;
CExternal* pThis = reinterpret_cast<CExternal*>(pParam);
if (pThis == NULL)
return 0;
// Init the com
::CoInitializeEx(0,COINIT_APARTMENTTHREADED);
hr = ::CoGetInterfaceAndReleaseStream(
pThis->m_pStream_,
IID_IHTMLDocument3,
(void**)&spDoc3);
if(FAILED(hr))
return 0;
while (pThis->m_bShutdown_ == 0)
{
if(pThis->m_TaskList_.size())
{
pTask = pThis->m_TaskList_.front();
pThis->m_TaskList_.pop_front();
if(pTask)
{
pTask->doTask(spDoc3); //do my custom task
delete pTask;
}
}
else
{
Sleep(10);
}
}
OutputDebugString(L"start CoUninitialize\n");
::CoUninitialize(); //release com
OutputDebugString(L"end CoUninitialize\n");
return 0;
}
The above the code that let my thread hang, the only output is "start CoUninitialize".
m_hWorker_ = (HANDLE)_beginthreadex(NULL, 0, WorkThread, this, 0, 0);
This code starts my thread, but the thread can't exit safely, so it waits. What the problem with this code?
The problem is not in this code, although it violates core COM requirements. Which says that you should release interface pointers when you no longer use them, calling IUnknown::Release(), and that an apartment-threaded thread must pump a message loop. Especially the message loop is important, you'll get deadlock when the owner thread of a single-threaded object (like a browser) is not pumping.
CoUninitialize() is forced to clean up the interface pointer wrapped by spDoc3 since you didn't do this yourself. It is clear from the code that the owner of the interface pointer actually runs on another thread, something to generally keep in mind since that pretty much defeats the point of starting your own worker thread. Creating your own STA thread doesn't fix this, it is still the wrong thread.
So the proxy needs to context switch to the apartment that owns the browser object. With the hard requirement that this apartment pumps a message loop so that the call can be dispatched on the right thread in order to safely call the Release() function. With very high odds that this thread isn't pumping messages anymore when your program is shutting down. Something you should be able to see in the debugger, locate the owner thread in the Debug + Windows + Threads window and see what it is doing.
Deadlock is the common outcome. The only good way to fix it is to shut down threads in the right order, this one has to shut down before the thread that owns the browser object. Shutting down a multi-threaded program cleanly can be quite difficult when threads have an interdependency like this. The inspiration behind the C++11 std::quick_exit() addition.

pthread_cond_wait never unblocking - thread pools

I'm trying to implement a sort of thread pool whereby I keep threads in a FIFO and process a bunch of images. Unfortunately, for some reason my cond_wait doesn't always wake even though it's been signaled.
// Initialize the thread pool
for(i=0;i<numThreads;i++)
{
pthread_t *tmpthread = (pthread_t *) malloc(sizeof(pthread_t));
struct Node* newNode;
newNode=(struct Node *) malloc(sizeof(struct Node));
newNode->Thread = tmpthread;
newNode->Id = i;
newNode->threadParams = 0;
pthread_cond_init(&(newNode->cond),NULL);
pthread_mutex_init(&(newNode->mutx),NULL);
pthread_create( tmpthread, NULL, someprocess, (void*) newNode);
push_back(newNode, &threadPool);
}
for() //stuff here
{
//...stuff
pthread_mutex_lock(&queueMutex);
struct Node *tmpNode = pop_front(&threadPool);
pthread_mutex_unlock(&queueMutex);
if(tmpNode != 0)
{
pthread_mutex_lock(&(tmpNode->mutx));
pthread_cond_signal(&(tmpNode->cond)); // Not starting mutex sometimes?
pthread_mutex_unlock(&(tmpNode->mutx));
}
//...stuff
}
destroy_threads=1;
//loop through and signal all the threads again so they can exit.
//pthread_join here
}
void *someprocess(void* threadarg)
{
do
{
//...stuff
pthread_mutex_lock(&(threadNode->mutx));
pthread_cond_wait(&(threadNode->cond), &(threadNode->mutx));
// Doesn't always seem to resume here after signalled.
pthread_mutex_unlock(&(threadNode->mutx));
} while(!destroy_threads);
pthread_exit(NULL);
}
Am I missing something? It works about half of the time, so I would assume that I have a race somewhere, but the only thing I can think of is that I'm screwing up the mutexes? I read something about not signalling before locking or something, but I don't really understand what's going on.
Any suggestions?
Thanks!
Firstly, your example shows you locking the queueMutex around the call to pop_front, but not round push_back. Typically you would need to lock round both, unless you can guarantee that all the pushes happen-before all the pops.
Secondly, your call to pthread_cond_wait doesn't seem to have an associated predicate. Typical usage of condition variables is:
pthread_mutex_lock(&mtx);
while(!ready)
{
pthread_cond_wait(&cond,&mtx);
}
do_stuff();
pthread_mutex_unlock(&mtx);
In this example, ready is some variable that is set by another thread whilst that thread holds a lock on mtx.
If the waiting thread is not blocked in the pthread_cond_wait when pthread_cond_signal is called then the signal will be ignored. The associated ready variable allows you to handle this scenario, and also allows you to handle so-called spurious wake-ups where the call to pthread_cond_wait returns without a corresponding call to pthread_cond_signal from another thread.
I'm not sure, but I think you don't have to (you must not) lock the mutex in the thread pool before calling pthread_cond_signal(&(tmpNode->cond)); , otherwise, the thread which is woken up won't be able to lock the mutex as part of pthread_cond_wait(&(threadNode->cond), &(threadNode->mutx)); operation.

Resources