How to make a child thread waiting for the main thread - c

I've got 2 threads : one child which detects mouse events, and the other main one which execute the program.
global variable :
int g_wait = 0;
child thread :
void *mouseEvent2(void *arg)
{
int fd;
struct input_event ev;
const char* pFile = "/dev/input/event0";
signal(SIGINT, SAMPLE_VGS_HandleSig);
signal(SIGTERM, SAMPLE_VGS_HandleSig);
fd = open(pFile, O_RDONLY);
if (fd == -1) {
printf("ERROR Opening %s\n", pFile);
return NULL;
}
while(scroll != -1) {
read(fd, &ev, sizeof(ev));
[... Some code with if statement ... ]
if(...) //left mouse button
g_wait = !g_wait;
[need waiting so the thread won't use at 100% a core]
}
close(fd);
(void) arg;
pthread_exit(NULL);
}
Main thread :
int main() {
[... some code and initilisation here ...]
if(pthread_create(&scrollThread, NULL, mouseEvent2, NULL))
goto _FAILURE_;
do {
[...]
while(g_wait);
}
[... some deinit ...]
_FAILURE_ :
pthread_join(scrollThread, NULL);
[... some other deinit ...]
return 0;
}
My problem is : when my main is waiting, my child thread is using at 100% 1 core processor, so which function can I use to pause the child thread with the main one?
I already consult How to make main thread wait for all child threads finish? but it didn't help me totally.

So, if you want to pause main thread until child thread signals about it ends, you can use mutexes to lock main thread:
#include "stdio.h"
#include "pthread.h"
/* I work on windows now, so i need windows sleep function to test example */
/* platform independed sleep function */
#ifdef _WIN32
# include "windows.h"
# define platform_sleep(ms) Sleep(ms)
#else
# include "unistd.h"
# define platform_sleep(s) sleep(s / 1000)
#endif
pthread_mutex_t mtx;
void *
child_func(void *arg)
{
/* simulate some hard work */
platform_sleep(3000); /* 3 secs */
/* after this "hard work" we allow main thread to continue */
pthread_mutex_unlock(&mtx);
}
int
main()
{
pthread_mutex_init(&mtx, NULL);
pthread_mutex_lock(&mtx);
pthread_t child;
pthread_create(&child, NULL, child_func, NULL);
/* mutex is already locked by main thread, so it waits */
/* until child thread unlock it */
pthread_mutex_lock(&mtx);
pthread_mutex_destroy(&mtx);
/* do work after child ends */
}

Related

Proper method to wait for exit conditions in threads

So reading this topic, the common way to exit would be using a flag. My question is, how is the waiting handled? Say the thread is only to run every 30s, how would you wait those 30s properly?
Using sem_timedwait() isn't ideal as it relies on the system clock and any change to the clock can severely impact your application. This topic explains using condition variables instead. The problem is, it relies on a mutex. You can't safely use pthread_mutex_lock() and pthread_mutex_unlock() in a signal handler. So in terms of my example above of 30s, if you want to exit immediately, who is handling the mutex unlock?
My guess would be another thread that sole purpose is to check the exit flag and if true it would unlock the mutex. However, what is that thread like? Would it not be wasted resources to just sit there constantly checking a flag? Would you use sleep() and check every 1s for example?
I don't believe my guess is a good one. It seems very inefficient and I run into similar "how do I wait" type of question. I feel like I'm missing something, but my searching is leading to topics similar to what I linked where it talks about flags, but nothing on waiting.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
pthread_mutex_t my_mutex;
volatile sig_atomic_t exitRequested = 0;
void signal_handler(int signum) {
exitRequested = 1;
}
bool my_timedwait(pthread_mutex_t *mutex, int seconds) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_t cond;
pthread_cond_init(&cond, &attr);
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
int status = pthread_cond_timedwait(&cond, mutex, &ts);
if (status == 0) {
return false; // mutex unlocked
}
if ((status < 0) && (status != ETIMEDOUT)) {
// error, do something
return false;
}
return true; // timedout
}
void *exitThread(void *ptr) {
// constant check???
while (1) {
if (exitRequested) {
pthread_mutex_unlock(&my_mutex);
break;
}
}
}
void *myThread(void *ptr) {
while (1) {
// do work
printf("test\n");
// wait and check for exit (how?)
if (!my_timedwait(&my_mutex, 30)) {
// exiting
break;
}
}
}
int main(void) {
// init and setup signals
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
// init the mutex and lock it
pthread_mutex_init(&my_mutex, NULL);
pthread_mutex_lock(&my_mutex);
// start exit thread
pthread_t exitHandler;
pthread_create(&exitHandler, NULL, exitThread, NULL);
// start thread
pthread_t threadHandler;
pthread_create(&threadHandler, NULL, myThread, NULL);
// wait for thread to exit
pthread_join(threadHandler, NULL);
pthread_join(exitHandler, NULL);
return EXIT_SUCCESS;
}
The solution is simple. Instead of having the first thread block in pthread_join, block that thread waiting for signals. That will ensure that a SIGINT can be handled synchronously.
You need a global structure protected by a mutex. It should count the number of outstanding threads and whether or not a shutdown is requested.
When a thread finishes, have it acquire the mutex, decrement the number of outstanding threads and, if it's zero, send a SIGINT. The main thread can loop waiting for a signal. If it's from the thread count going to zero, let the process terminate. If it's from an external signal, set the shutdown flag, broadcast the condition variable, unlock the mutex, and continue waiting for the thread count to hit zero.
Here's a start:
pthread_mutex_t my_mutex; // protects shared state
pthread_cond_t my_cond; // allows threads to wait some time
bool exitRequested = 0; // protected by mutex
int threadsRunning = 0; // protected by mutex
pthread_t main_thread; // set in main
bool my_timedwait(int seconds)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
pthread_mutex_lock (&my_mutex);
while (exitRequested == 0)
{
int status = pthread_cond_timedwait(&my_cond, &my_mutex, &ts);
if (status == ETIMEDOUT) // we waited as long as supposed to
break;
}
bool ret = ! exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret; // timedout
}
bool shuttingDown()
{
pthread_mutex_lock (&my_mutex);
bool ret = exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret;
}
void requestShutdown()
{
// call from the main thread if a SIGINT is received
pthread_mutex_lock (&my_mutex);
exitRequested = 1;
pthread_cond_broadcast (&my_cond);
pthread_mutex_unlock (&my_mutex);
}
void threadDone()
{
// call when a thread is done
pthread_mutex_lock (&my_mutex);
if (--threadsRunning == 0)
pthread_kill(main_thread, SIGINT); // make the main thread end
pthread_mutex_unlock (&my_mutex);
}

How to create a thread for signal handling and exit the process upon receiving the signal?

I written the below code to handle signals in separate thread to forcefully cleanup some resources and exit the complete process.
Here is the brief note about the below code.
When the signal is received, set volatile sig_atomic_t sig_set_flag = 1; inside signal handler.
In signal_handler_thread, checking sig_set_flag value in a loop.
if(sig_set_flag==1) send notifications like "i am going down" from signal_handler_thread and call exit(0); from the thread.
Signals can be received by any thread in a process. So i am setting the global variable.
I have 2 questions.
1) This implementation is fine? or i have to block the signals for the main thread and handle only by the spawned thread ?
2) How to block a signal to the main process and handle it in a thread?
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
/*
* Set this variable if any signal is received
*/
volatile sig_atomic_t sig_set_flag = 0;
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread
*/
void sig_term_handler(int sig_num) {
sig_set_flag = sig_num;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
while(1) {
if(sig_set_flag != 0) {
printf("%s : Signal flag is set for sig_no %d\n",__func__,sig_set_flag);
cleaup_resources();
break;
}
usleep(5);
}
exit(0);
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
struct sigaction sig;
sig.sa_handler = &sig_term_handler;
sig.sa_flags = 0;
sigaction(SIGTERM, &sig, NULL);
/*
* Spawn a thread to monitor signals.
* If signal received, Exit the process.
*/
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}
Note:I know signals will interrupt the some system calls and EINTR will be set. Unfortunately some system calls (i.e) waitpid() will not be interrupted. So i spawned a thread to handle this scenario.
1) Your implementation seems to be correct. signal() and sigaction() register a handler function for the whole process, so it doesn't matter you call them in the main thread or in the spawned thread.
2) To block a signal in the main thread, and handle it in a thread, you have to design, not a handler function, but a handler thread, using sigwait() or sigwaitinfo(). So the thread will wait for the signals and the program execution won't be interrupted.
In this case, you have to block process-wide signals in all the threads, including the main thread. If it is not blocked, the signal will have the default behavior on the program.
You have to use pthread_sigmask() to block one or more signals. An example of code to block SIGTERM:
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGTERM);
pthread_sigmask(SIG_BLOCK,&set,NULL);
When a thread is created, it inherits of the blocked signals of the creator thread.
I modified your code to show you how to use sigwaitinfo() and pthread_sigmask():
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
siginfo_t info;
while(1) {
sigwaitinfo(&set,&info);
if(info.si_signo == SIGINT){
printf("\nSIGINT received\n");
cleaup_resources();
exit(0);
}
}
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_BLOCK,&set,NULL);
// The new thread will inherit the blocked
// signals from the thread that create it:
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}
Also, be careful of the fork(), from the tests I have done, the child process will inherit of the blocked signals.

pthread_cond_timedwait call is not working with mutex locking mechanism

I have a logging application. In which after specific time (user configureable time) i need to close the current log file and and create a new log file and log the data.
There are 2 critical sections of code in my program.
Writing the data to file (in while(1))
Close and open the new file
Whenever time expires i need to stop the logging to the file and close it & open the new log file and start logging.
For this purpose i have created a sample application exactly same as my application, but instead of file operation here am doing with printf.
I am using pthread_cond_timedwait call to handle the timer related operation. Here is my sample code -
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
/* For safe condition variable usage, must use a boolean predicate and */
/* a mutex with the condition. */
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
#define WAIT_TIME_SECONDS 10
void *threadfunc(void *parm)
{
int rc;
struct timespec abstime;
struct timeval now;
/* Usually worker threads will loop on these operations */
while (1) {
rc = gettimeofday(&now, NULL);
/* Convert from timeval to timespec */
abstime.tv_sec = now.tv_sec + WAIT_TIME_SECONDS;
abstime.tv_nsec = (now.tv_usec + 1000UL * WAIT_TIME_SECONDS) * 1000UL;
abstime.tv_sec += abstime.tv_nsec / (1000 * 1000 * 1000);
abstime.tv_nsec %= (1000 * 1000 * 1000);
printf("Thread blocked\n");
pthread_mutex_lock(&mutex);
rc = pthread_cond_timedwait(&cond, &mutex, &abstime);
pthread_mutex_unlock(&mutex);
printf("Wait timed out!\n");
/* critical section of code */
pthread_mutex_lock(&lock);
printf("Thread consumes work here\n");
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(int argc, char **argv)
{
int rc=0;
pthread_t threadid;
rc = pthread_create(&threadid, NULL, threadfunc, NULL);
if (rc != 0) {
printf("Thread creation failed err:%d\n", errno);
return -1;
}
while (1) {
/* critical section of code */
sleep(1);
pthread_mutex_lock(&lock);
printf("One work item to give to a thread\n");
pthread_mutex_unlock(&lock);
}
printf("Wait for threads and cleanup\n");
pthread_join(threadid, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
printf("Main completed\n");
return 0;
}
This code is not working. Whenever pthread_cond_timedwait expires threadfunc function should acquire mutex lock and it needs print the statements. After printing am releasing the mutex. But it is not happening. Control is never transfered from main() to threadfunc. Whats is going wrong here?
But instead of mutex if i use a variable to do the handling of critical section of code am able to do it. Say -
static int stop = 0; // take a global variable
//inside threadfunc
/* critical section of code */
stop = 1; //Replace pthread_mutex_lock with this
printf("Thread consumes work here\n");
stop = 0; //Replace pthread_mutex_unlock with this
//in main()
while (1) {
/* critical section of code */
sleep(1);
if (!stop)
printf("One work item to give to a thread\n");
}
This approach is working fine.
When i am using more then one mutex in my code am not able to implement this. What is the real thing happening behind? Am i missing anything while am using mutex to handle critical section of a code?
Thanks in advance!

sigwait() and signal handler

If I setup and signal handler for SIGABRT and meanwhile I have a thread that waits on sigwait() for SIGABRT to come (I have a blocked SIGABRT in other threads by pthread_sigmask).
So which one will be processed first ? Signal handler or sigwait() ?
[I am facing some issues that sigwait() is get blocked for ever. I am debugging it currently]
main()
{
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigprocmask(SIG_BLOCK, &signal_set, NULL);
// Dont deliver SIGABORT while running this thread and it's kids.
pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
pthread_create(&tAbortWaitThread, NULL, WaitForAbortThread, NULL);
..
Create all other threads
...
}
static void* WaitForAbortThread(void* v)
{
sigset_t signal_set;
int stat;
int sig;
sigfillset( &signal_set);
pthread_sigmask( SIG_BLOCK, &signal_set, NULL ); // Dont want any signals
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT); // Add only SIGABRT
// This thread while executing , will handle the SIGABORT signal via signal handler.
pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
stat= sigwait( &signal_set, &sig ); // lets wait for signal handled in CatchAbort().
while (stat == -1)
{
stat= sigwait( &signal_set, &sig );
}
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
// Abort signal handler executed via sigaction().
static void CatchAbort(int i, siginfo_t* info, void* v)
{
sleep(20); // Dont return , hold on till the other threads are down.
}
Here at sigwait(), i will come to know that SIGABRT is received. I will tell other threads about it. Then will hold abort signal handler so that process is not terminated.
I wanted to know the interaction of sigwait() and the signal handler.
From sigwait() documentation :
The sigwait() function suspends execution of the calling thread until
one of the signals specified in the signal set becomes pending.
A pending signal means a blocked signal waiting to be delivered to one of the thread/process. Therefore, you need not to unblock the signal like you did with your pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL) call.
This should work :
static void* WaitForAbortThread(void* v){
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigwait( &signal_set, &sig );
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
I got some information from this <link>
It says :
To allow a thread to wait for asynchronously generated signals, the threads library provides the sigwait subroutine. The sigwait subroutine blocks the calling thread until one of the awaited signals is sent to the process or to the thread. There must not be a signal handler installed on the awaited signal using the sigwait subroutine.
I will remove the sigaction() handler and try only sigwait().
From the code snippet you've posted, it seems you got the use of sigwait() wrong. AFAIU, you need WaitForAbortThread like below:
sigemptyset( &signal_set); // change it from sigfillset()
for (;;) {
stat = sigwait(&signal_set, &sig);
if (sig == SIGABRT) {
printf("here's sigbart.. do whatever you want.\n");
pthread_kill(tid, signal); // thread id and signal
}
}
I don't think pthread_sigmask() is really needed. Since you only want to handle SIGABRT, first init signal_set as empty then simply add SIGABRT, then jump into the infinite loop, sigwait will wait for the particular signal that you're looking for, you check the signal if it's SIGABRT, if yes - do whatever you want. NOTE the uses of pthread_kill(), use it to sent any signal to other threads specified via tid and the signal you want to sent, make sure you know the tid of other threads you want to sent signal. Hope this will help!
I know this question is about a year old, but I often use a pattern, which solves exactly this issue using pthreads and signals. It is a little length but takes care of any issues I am aware of.
I recently used in combination with a library wrapped with SWIG and called from within Python. An annoying issue was that my IRQ thread waiting for SIGINT using sigwait never received the SIGINT signal. The same library worked perfectly when called from Matlab, which didn't capture the SIGINT signal.
The solution was to install a signal handler
#define _NTHREADS 8
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> // strerror
#define CallErr(fun, arg) { if ((fun arg)<0) \
FailErr(#fun) }
#define CallErrExit(fun, arg, ret) { if ((fun arg)<0) \
FailErrExit(#fun,ret) }
#define FailErrExit(msg,ret) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr); \
return ret; }
#define FailErr(msg) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr);}
typedef struct thread_arg {
int cpu_id;
int thread_id;
} thread_arg_t;
static jmp_buf jmp_env;
static struct sigaction act;
static struct sigaction oact;
size_t exitnow = 0;
pthread_mutex_t exit_mutex;
pthread_attr_t attr;
pthread_t pids[_NTHREADS];
pid_t tids[_NTHREADS+1];
static volatile int status[_NTHREADS]; // 0: suspended, 1: interrupted, 2: success
sigset_t mask;
static pid_t gettid( void );
static void *thread_function(void *arg);
static void signalHandler(int);
int main() {
cpu_set_t cpuset;
int nproc;
int i;
thread_arg_t thread_args[_NTHREADS];
int id;
CPU_ZERO( &cpuset );
CallErr(sched_getaffinity,
(gettid(), sizeof( cpu_set_t ), &cpuset));
nproc = CPU_COUNT(&cpuset);
for (i=0 ; i < _NTHREADS ; i++) {
thread_args[i].cpu_id = i % nproc;
thread_args[i].thread_id = i;
status[i] = 0;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&exit_mutex, NULL);
// We pray for no locks on buffers and setbuf will work, if not we
// need to use filelock() on on FILE* access, tricky
setbuf(stdout, NULL);
setbuf(stderr, NULL);
act.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT;
act.sa_handler = signalHandler;
sigemptyset(&act.sa_mask);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
if (setjmp(jmp_env)) {
if (gettid()==tids[0]) {
// Main Thread
printf("main thread: waiting for clients to terminate\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
if (status[i] == 1)
printf("thread %d: terminated\n",i+1);
}
// On linux this can be done immediate after creation
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
else {
// Should never happen
printf("worker thread received signal");
}
return -1;
}
// Install handler
CallErr(sigaction, (SIGINT, &act, &oact));
// Block SIGINT
CallErr(pthread_sigmask, (SIG_BLOCK, &mask, NULL));
tids[0] = gettid();
srand ( time(NULL) );
for (i = 0; i < _NTHREADS; i++) {
// Inherits main threads signal handler, they are blocking
CallErr(pthread_create,
(&pids[i], &attr, thread_function,
(void *)&thread_args[i]));
}
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) {
fprintf(stderr, "main thread: can't block SIGINT");
}
printf("Infinite loop started - CTRL-C to exit\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
//printf("%d\n",status[i]);
if (status[i] == 2)
printf("thread %d: finished succesfully\n",i+1);
}
// Clean up and exit
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
static void signalHandler(int sig) {
int i;
pthread_t id;
id = pthread_self();
for (i = 0; i < _NTHREADS; i++)
if (pids[i] == id) {
// Exits if worker thread
printf("Worker thread caught signal");
break;
}
if (sig==2) {
sigaction(SIGINT, &oact, &act);
}
pthread_mutex_lock(&exit_mutex);
if (!exitnow)
exitnow = 1;
pthread_mutex_unlock(&exit_mutex);
longjmp(jmp_env, 1);
}
void *thread_function(void *arg) {
cpu_set_t set;
thread_arg_t* threadarg;
int thread_id;
threadarg = (thread_arg_t*) arg;
thread_id = threadarg->thread_id+1;
tids[thread_id] = gettid();
CPU_ZERO( &set );
CPU_SET( threadarg->cpu_id, &set );
CallErrExit(sched_setaffinity, (gettid(), sizeof(cpu_set_t), &set ),
NULL);
int k = 8;
// While loop waiting for exit condition
while (k>0) {
sleep(rand() % 3);
pthread_mutex_lock(&exit_mutex);
if (exitnow) {
status[threadarg->thread_id] = 1;
pthread_mutex_unlock(&exit_mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&exit_mutex);
k--;
}
status[threadarg->thread_id] = 2;
pthread_exit(NULL);
}
static pid_t gettid( void ) {
pid_t pid;
CallErr(pid = syscall, (__NR_gettid));
return pid;
}
I run serveral tests and the conbinations and results are:
For all test cases, I register a signal handler by calling sigaction in the main thread.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A sleep, send target signal.
result: signal handler is executed in thread A.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A calls sigwait, send target signal.
result: sigwait is executed.
main thread does not block target signal, thread A does not block target signal, thread A calls sigwait, send target signal.
result: main thread is chosen and the registered signal handler is executed in the main thread.
As you can see, conbination 1 and 2 are easy to understand and conclude.
It is:
If a signal is blocked by a thread, then the process-wide signal handler registered by sigaction just can't catch or even know it.
If a signal is not blocked, and it's sent before calling sigwait, the process-wide signal handler wins. And that's why APUE the books require us to block the target signal before calling sigwait. Here I use sleep in thread A to simulate a long "window time".
If a signal is not blocked, and it's sent when sigwait has already been waiting, sigwait wins.
But you should notice that for test case 1 and 2, main thread is designed to block the target signal.
At last for test case 3, when main thread is not blocked the target signal, and sigwait in thread A is also waiting, the signal handler is executed in the main thread.
I believe the behaviour of test case 3 is what APUE talks about:
From APUE ยง12.8:
If a signal is being caught (the process has established a signal
handler by using sigaction, for example) and a thread is waiting for
the same signal in a call to sigwait, it is left up to the
implementation to decide which way to deliver the signal. The
implementation could either allow sigwait to return or invoke the
signal handler, but not both.
Above all, if you want to accomplish one thread <-> one signal model, you should:
block all signals in the main thread with pthread_sigmask (subsequent thread created in main thread inheris the signal mask)
create threads and call sigwait(target_signal) with target signal.
test code
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
FILE* file;
void* threadA(void* argv){
fprintf(file, "%ld\n", pthread_self());
sigset_t m;
sigemptyset(&m);
sigaddset(&m, SIGUSR1);
int signo;
int err;
// sigset_t q;
// sigemptyset(&q);
// pthread_sigmask(SIG_SETMASK, &q, NULL);
// sleep(50);
fprintf(file, "1\n");
err = sigwait(&m, &signo);
if (err != 0){
fprintf(file, "sigwait error\n");
exit(1);
}
switch (signo)
{
case SIGUSR1:
fprintf(file, "SIGUSR1 received\n");
break;
default:
fprintf(file, "?\n");
break;
}
fprintf(file, "2\n");
}
void hello(int signo){
fprintf(file, "%ld\n", pthread_self());
fprintf(file, "hello\n");
}
int main(){
file = fopen("daemon", "wb");
setbuf(file, NULL);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = hello;
sigaction(SIGUSR1, &sa, NULL);
sigset_t n;
sigemptyset(&n);
sigaddset(&n, SIGUSR1);
// pthread_sigmask(SIG_BLOCK, &n, NULL);
pthread_t pid;
int err;
err = pthread_create(&pid, NULL, threadA, NULL);
if(err != 0){
fprintf(file, "create thread error\n");
exit(1);
}
pause();
fprintf(file, "after pause\n");
fclose(file);
return 0;
}
run with ./a.out & (run in the background), and use kill -SIGUSR1 pid to test. Do not use raise. raise, sleep, pause are thread-wide.

Pthread create as detached

I have a problem creating a thread as detached. Here's the code I wrote:
void* testFunction() {
pthread_attr_t attr;
int chk,rc;
pthread_attr_init(&attr);
printf("thread_attr_init: %d\n",rc);
pthread_attr_getdetachstate(&attr, &chk);
printf("thread_attr_getdetachedstate: %d\n",rc);
if(chk == PTHREAD_CREATE_DETACHED )
printf("Detached\n");
else if (chk == PTHREAD_CREATE_JOINABLE)
printf("Joinable\n");
return NULL;
}
int main (int argc, const char * argv[]) {
pthread_t thread1;
pthread_attr_t attr;
int rc;
rc = pthread_attr_init(&attr);
printf("attr_init: %d\n",rc);
rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
printf("attr_setdetachedstate: %d\n",rc);
rc = pthread_create(&thread1, &attr, testFunction, NULL);
printf("attr_create: %d\n",rc);
sleep(4);
pthread_cancel(thread1);
return 0;
}
The problem is that testFunction() always print "Joinable". Can anyone tell me where I'm getting wrong?
Try running the following code. That should clear the confusion.
/*------------------------------- join_01.c --------------------------------*
On Linux, compile with:
cc -std=c99 -pthread join_01.c -o join_01
gcc join_01.c -o join_01 -std=c99 -lpthread (Ubuntu)
Check your system documentation how to enable C99 and POSIX threads on
other Un*x systems.
Copyright Loic Domaigne.
Licensed under the Apache License, Version 2.0.
*--------------------------------------------------------------------------*/
#include <unistd.h> // sleep()
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> // EXIT_SUCCESS
#include <string.h> // strerror()
#include <errno.h>
/***************************************************************************/
/* our macro for errors checking */
/***************************************************************************/
#define COND_CHECK(func, cond, retv, errv) \
if ( (cond) ) \
{ \
fprintf(stderr, "\n[CHECK FAILED at %s:%d]\n| %s(...)=%d (%s)\n\n",\
__FILE__,__LINE__,func,retv,strerror(errv)); \
exit(EXIT_FAILURE); \
}
#define ErrnoCheck(func,cond,retv) COND_CHECK(func, cond, retv, errno)
#define PthreadCheck(func,rc) COND_CHECK(func,(rc!=0), rc, rc)
/*****************************************************************************/
/* thread- dummy thread */
/*****************************************************************************/
void*
thread(void* ignore)
{
sleep(1);
return NULL;
}
/*****************************************************************************/
/* detach_state. Print detachstate of a thread. */
/*****************************************************************************/
/*
* We find out indirectly if a thread is detached using pthread_join().
* If a thread is detached, then pthread_join() fails with EINVAL.
* Otherwise the thread is joined, and hence was joinable.
*
*/
void
detach_state(
pthread_t tid, // thread to check detach status
const char *tname // thread name
)
{
int rc; // return code
rc = pthread_join(tid, NULL);
if ( rc==EINVAL )
{
printf("%s is detached\n", tname);
}
else if ( rc==0 )
{
printf("%s was joinable\n", tname);
}
else
{
printf("%s: pthread_join() = %d (%s)\n",
tname, rc, strerror(rc)
);
}
}
/*****************************************************************************/
/* main- main thread */
/*****************************************************************************/
int
main()
{
pthread_t tid1, tid2, tid3; // thread 1,2 and 3.
pthread_attr_t attr; // thread's attribute
int rc; // return code
/*--------------------------------------------------------*/
/* 1st test: normal thread creation */
/*--------------------------------------------------------*/
rc = pthread_create(&tid1, NULL, thread, NULL);
PthreadCheck("pthread_create", rc);
detach_state(tid1, "thread1"); // expect: joinable
/*--------------------------------------------------------*/
/* 2nd test: detach thread from main thread */
/*--------------------------------------------------------*/
rc = pthread_create(&tid2, NULL, thread, NULL);
PthreadCheck("pthread_create", rc);
rc = pthread_detach(tid2);
PthreadCheck("pthread_detach", rc);
detach_state(tid2, "thread2"); // expect: detached
/*--------------------------------------------------------*/
/* 3rd test: create detached thread */
/*--------------------------------------------------------*/
// set detachstate attribute to DETACHED
//
rc=pthread_attr_init(&attr);
PthreadCheck("pthread_attr_init", rc);
rc=pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
PthreadCheck("pthread_attr_setdetachstate", rc);
// create thread now
//
rc = pthread_create(&tid3, &attr, thread, NULL);
PthreadCheck("pthread_create", rc);
detach_state(tid3, "thread3");
/*--------------------------------------------------------*/
/* that's all folks! */
/*--------------------------------------------------------*/
return EXIT_SUCCESS;
}
The output should be
$ ./join_01
thread1 was joinable
thread2 is detached
thread3 is detached
Your testFunction is not examining anything about the current thread, rather just the initially-detached flag of a completely new attribute object you just created. Moreover, it is completely impossible, in the POSIX threads API, to recover the attributes a thread was created with or determine if a thread is detached or not. You simply have to trust that the implementation behaves as required, just like you have to trust that, if malloc(100) returns a non-null pointer, it points to a location at which you can store at least 100 bytes. This is the nature of C.
Your testFunction is not reading the current thread's attributes. Instead of calling pthread_attr_init(), pthread_getattr_np() might help you if it's present on your system, but you will need to pass the pthread_t for the thread in question onto wherever it's being queried from.

Resources