Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

posix threads block signal and unblock

Is there a way to block certain signals and unblock other signals in the same set? I just dont seem to get my head around it!

An example

sigset_t set;
sigemptyset(&set);

sigaddset(&set, SIGUSR1);
// Block signal SIGUSR1 in this thread
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigaddset(&set, SIGALRM);
// Listen to signal SIGUSR2
pthread_sigmask(SIG_UNBLOCK, &set, NULL);


pthread_t printer_thread1, printer_thread2;
pthread_create(&printer_thread1, NULL, print, (void *)&f1);
pthread_create(&printer_thread2, NULL, print, (void *)&f2);

bool tl = true;
while(1)
{
    if(tl)
    {
        // thread1 does something
        kill(pid, SIGUSR1);
        // main thread waits for SIGALRM
        sigwait(&set, &sig);
        tl = !tl;
    }
    else
    {
        // thread2 does something
        kill(pid, SIGUSR2);
        // main thread waits for SIGALRM
        sigwait(&set, &sig);
        tl = !tl;
    }
}

I am not allowed to use Mutexs, semaphores etc only signals.

Can someone help? :)

like image 517
Max Avatar asked Oct 29 '12 00:10

Max


People also ask

How do Posix threads work?

The POSIX thread libraries are a standards based thread API for C/C++. It allows one to spawn a new concurrent process flow. It is most effective on multi-processor or multi-core systems where the process flow can be scheduled to run on another processor thus gaining speed through parallel or distributed processing.

Do threads inherit signal mask?

A new thread inherits a copy of its creator's signal mask. The glibc pthread_sigmask() function silently ignores attempts to block the two real-time signals that are used internally by the NPTL threading implementation.

What does pthread_ sigmask do?

pthread_sigmask() examines, changes, or examines and changes the signal mask of the calling thread. If there is only one thread, it does the same for the calling process. Typically, pthread_sigmask(SIG_BLOCK, ..., ...) is used to block signals during a critical section of code.

What is signal blocking?

Blocking a signal means telling the operating system to hold it and deliver it later. Generally, a program does not block signals indefinitely—it might as well ignore them by setting their actions to SIG_IGN . But it is useful to block signals briefly, to prevent them from interrupting sensitive operations.


2 Answers

Is there a way to block certain signals and unblock other signals in the same set?

With pthread_sigmask, you can choose to either:

  • add a set of signals to the set of blocked signals, using the constant SIG_BLOCK
  • remove a set of signals to the set of blocked signals, using the constant SIG_UNBLOCK
  • define the set of signals to be blocked, using the constant SIG_SET

In other words, there's a current set of blocked signals for the thread, and you can modify it as specified above, one operation at a time.

The important point is that newly created threads inherit the signal mask of the creating thread, so you can set the mask of the new thread right before creating it, or in the function that the new thread will run, at your convenience.

Regarding your example, I suppose that you are trying to have printer_thread1 block SIGUSR2 and SIGALRM, and have printer_thread2 block SIGUSR1 and SIGALRM, and have the main thread block SIGUSR1 and SIGUSR2, so that each thread can send a signal that will be caught by a single thread (without the code of print, f1 and f2, it's impossible to know for sure what is your intent in your example).

You should be able to achieve that by the following code:

sigset_t set;
pthread_t printer_thread1, printer_thread2;


// Block signal SIGUSR1 & SIGALRM in printer_thread1
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_SET, &set, NULL);
pthread_create(&printer_thread1, NULL, print, (void *)&f1);

// Block signal SIGUSR2 & SIGALRM in printer_thread2
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_SET, &set, NULL);
pthread_create(&printer_thread2, NULL, print, (void *)&f2);

// Block signal SIGUSR1 & SIGUSR2 in the main thread
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
// Listen to signal SIGALRM
pthread_sigmask(SIG_SET, &set, NULL);


bool tl = true;
while(1)
{
    if(tl)
    {
        // thread1 does something
        kill(pid, SIGUSR1);
        // main thread waits for SIGALRM
        sigwait(&set, &sig);
        tl = !tl;
    }
    else
    {
        // thread2 does something
        kill(pid, SIGUSR2);
        // main thread waits for SIGALRM
        sigwait(&set, &sig);
        tl = !tl;
    }
}

see these man pages :

  • pthread_sigmask
  • sigprocmask

for further details.

like image 100
didierc Avatar answered Oct 23 '22 00:10

didierc


I think what you want to do here is

// Block signal SIGUSR1 in this thread
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &set, NULL);

// Listen to signal SIGALRM
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);

The set is only used to tell it what to block or unblock. Once passed to the command, you are free to reset it and build up another signal mask. If you skip the sigemptyset, the set will still contain SIGUSR1, which will subsequently be unblocked again. Well, I think that is how it works, at least - it has been a long time since I used signals.

like image 34
amaurea Avatar answered Oct 23 '22 00:10

amaurea