I'm brand new to c programming and am struggling with an assignment. The basics of the code is to have a 1 second timer (I'm using sleep(1)) that counts up starting with an increment of 1. Every time I send sigINT, I increase the increment by 1 and the counter prints off the new number. I use sigterm to decrement the number. All of this is working fine.
The last part is to kill the program if I use sigINT twice in one second. I have tried doing this with a "flag" which for me is set to 0. When the sigINT is called, increase it by 1. Have it reset to 0 in my while loop. I tried writing an if statement that if the increment is more than 1, the program would stop. But with sleep(0) and flag=0 right after that, I can never get the flag to be more than 1. I know this probably isn't the best way to do this, but have had no luck in finding a better solution. Any help is appreciated. Thanks.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int inc = 1;
int flag = 0;
void handle_sigint(int sig_num)
{
signal(SIGINT, handle_sigint);
if (inc < 10)
{
inc++;
}
flag++;
printf("\nflag=%d\n", flag);
printf("\nSIGINT received: Increment is now %d\n", inc);
fflush(stdout);
}
void handle_sigterm(int sig_num)
{
signal(SIGTERM, handle_sigterm);
if (inc > 0)
{
inc--;
}
printf("\nSIGTERM received: Increment is now %d\n", inc);
fflush(stdout);
}
int main()
{
int num = 0;
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigterm);
printf("Process ID: %d\n", getpid());
while (1)
{
if (flag > 1)
{
pid_t iPid = getpid();
printf("\nExiting the program now\n");
kill(iPid, SIGKILL);
}
printf("%d\n", num);
num = num + inc;
sleep(1);
flag = 0;
}
return 0;
}
If are setting flag=0 right after sleep(1) and right before checking if(flag>1). That means there is no time between setting it to zero and checking, and in that time you want to send to SIGINT signals to your program. You have set the flag to zero at best right after checking it.
sleep() call is interruptible! If sleep() is interrupted by the signal, it returns the number of seconds left to sleep. For reference read man sleep. As "1 second" is not really divisible by a smaller chunk, you could use usleep or just use nanosleep call. nanosleep returns -1 and sets errno to EINTR if signal was received during sleep. Because it returns the time left to sleep in the second argument, it's easy to do a loop with it. You have to add #include <errno.h> for errno and #include <time.h> for nanosleep.
So something along:
while (1) {
if (flag > 1) {
// some code
}
// printf("something");
// set flag before sleeping!
flag = 0;
// wait a second
struct timespec rqtp = { 1, 0 };
while (nanosleep(&rqtp, &rqtp) == -1 && errno == EINTR) {
// repeat until we slept a full second
}
}
Notes:
Good code! Please follow some indentation style and indent your code. I recommend linux kernel coding style.
printf and fflush are not signal-safe function. Calling them from a signal handler is undefined behavior. You should not call printf from a signal handler.
Technically volatile sig_atomic_t type should be used to synchronize with a signal handler. I guess it would be preferable to mark your flag and inc variables at least as volatile.
While reading up and learning about signals, I found a program, that uses signals in a specific way. I tried understand it, but I am not sure, how all the parts of the code interact with another.
Below is the above mentioned code and I added comments, where I have difficulties:
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define CP 5
static volatile int curprocs =0; ;
static void die() {
exit(EXIT_FAILURE);
}
static void chldhandler() {
int e = errno;
// Why do we use waitpid here? What does it do?
while(waitpid(-1, NULL, WNOHANG) > 0) {
curprocs--;
}
errno = e;
}
void do_work() {
time_t t;
srand((unsigned) time(&t));
sleep(5+ rand() % 4);
}
int main() {
struct sigaction sa = {
.sa_handler = chldhandler,
.sa_flags = SA_RESTART,
};
sigemptyset(&sa.sa_mask);
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
exit(-1);
}
while(1) {
sigset_t chld, empty;
sigemptyset(&empty);
sigemptyset(&chld);
sigaddset(&chld, SIGCHLD);
// What do the following lines of code do??
sigprocmask(SIG_BLOCK, &chld, NULL);
while (curprocs >= CP) { // cap for the number of child processes
sigsuspend(&empty);
}
curprocs++;
sigprocmask(SIG_UNBLOCK, &chld, NULL);
pid_t p = fork();
if (p == -1) {
return -1;
}
if (p == 0) {
// code for the child processes to execute
do_work();
die();
} else {
// Parent process does nothing
}
}
return 0;
}
Obviously above program is intended to have a max amount of 42 child processes doing work. Whenever we want to have a new child process, we use fork, and adjust curprocs.
Whenever a child process finishes, chldhandler() is called and curprocs is adjusted as well.
However I don't understand the interplay of the two sigproc_mask, sigsuspend, waitpid and our two signalsets chld, empty.
Can someone explain what these lines do or why they are used the way they are?
sigprocmask(SIG_BLOCK, &chld, NULL); blocks SIGCHLD so that you can be sure that while you do while (curprocs >= 42) the SIGCHLD handler won't interrupt the code, changing curprocs in the middle of the check.
sigsuspends atomically unblocks it and waits for a SIGCHLD (any signal really, since your passing an empty mask), atomically reblocking it when it returns.
The waitpid(-1,/*...*/) in the handler reaps the status of any (that's what the -1 means) child that has a status change (typically termination notification) pending so that the data the kernel associates with the status change can be freed. The second argument would be where the status change info would go but since you passed NULL, the info will simply be dropped. WNOHANG means don't wait if there aren't any more status change notifications.
Since the handler is run in response to SIGCHLD, there should be at least one status change notification, but there could be more because SIGCHLDs can coalesce (it's also possible there isn't any — if you called waitpid from normal context while SIGCHLD was blocked). That's why the handler loops. The WNOHANG is important because without it, after all the status change notifications have been reaped, the waitpid call would block your process until a new notification arrived.
im trying to implement this:
Make a C multi-process program that does the following:
A process P generates two child processes P1 and P2. The two sons P1 and P2 perform an indeterminate cycle in which generate, each second, a random integer between 0 and 100. With each draw, the children communicate the numbers generated by the parent P process which provides for adding them, printing them on the screen and storing them in one file. Process P1 must handle the SIGINT interrupt signal. In particular, at the arrival of this signal P1 must display the warning message "P1 process busy!". The program is terminated by the parent P process when it verifies that the sum of the numbers, which it has received from the child processes, assumes the value 100.
Now, I need some help with the synchronization between childs and parent. Im trying to use semaphores but it looks like impossible. what can i use to synchronize them? signals? how?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#define READ 0
#define WRITE 1
void handler(int sig){
printf("process 1 is busy\n");
}
void codeprocess1(int pd[], sem_t *sem1){
int i = 0;
int numgenerated;
while( i = 0){
signal(SIGUSR1, handler);
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem1);
}
}
void codeprocess2(int pd[], sem_t *sem2){
int i = 0;
int numgenerated;
while( i = 0){
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem2);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
sem_t *sem2 = sem_open("semaph2", O_CREAT | O_EXCL, 1, 0);
sem_t *sem1 = sem_open("semaph1", O_CREAT | O_EXCL, 1, 0);
if(pipe(pipe1)<0){
exit(1);
}
if(pipe(pipe2)<0){
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1, sem1);
break;
default:
pid2= fork();
switch( pid2){
case -1:
exit(1);
case 0:
codeprocess2(pipe2, sem2);
break;
default:
while(sum!=1000){
close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
sum = sum + numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
I'm reporting here the relevant part of the man page of sem_overview(7):
POSIX semaphores come in two forms: named semaphores and unnamed sema‐
phores.
Named semaphores
A named semaphore is identified by a name of the form /somename;
that is, a null-terminated string of up to NAME_MAX-4 (i.e.,
251) characters consisting of an initial slash, followed by one
or more characters, none of which are slashes. Two processes
can operate on the same named semaphore by passing the same name
to sem_open(3).
The sem_open(3) function creates a new named semaphore or opens
an existing named semaphore. After the semaphore has been
opened, it can be operated on using sem_post(3) and sem_wait(3).
When a process has finished using the semaphore, it can use
sem_close(3) to close the semaphore. When all processes have
finished using the semaphore, it can be removed from the system
using sem_unlink(3).
Unnamed semaphores (memory-based semaphores)
An unnamed semaphore does not have a name. Instead the sema‐
phore is placed in a region of memory that is shared between
multiple threads (a thread-shared semaphore) or processes (a
process-shared semaphore). A thread-shared semaphore is placed
in an area of memory shared between the threads of a process,
for example, a global variable. A process-shared semaphore must
be placed in a shared memory region (e.g., a System V shared
memory segment created using shmget(2), or a POSIX shared memory
object built created using shm_open(3)).
Before being used, an unnamed semaphore must be initialized
using sem_init(3). It can then be operated on using sem_post(3)
and sem_wait(3). When the semaphore is no longer required, and
before the memory in which it is located is deallocated, the
semaphore should be destroyed using sem_destroy(3).
You are trying to use unnamed semaphores in standard memory. But they are meant to synchronize threads only, not processes.
I suggest to use either named semaphores (that should be easier) or unnamed semaphores backed by shared memory (get it with shmget() or shm_open(), then use it with sem_init() - the parent and the forked processes must use the same shared memory segment to have access to the inter-process semaphore).
In fact, in your code sem1 and sem2, initialized in the main process, won't be propagated to the forked processes: they have independent memory regions and addresses, and cannot be shared.
After the edit, regarding the semaphores there are many problems:
the most logically wrong: you cannot pass the pointer of one process to another process: the addresses are not shared. Every process must independently open the semaphore and use it with his own handler.
while (i=0)... ouch, try compiling with -Wall.
You wasn't checking the return code of sem_open() it was failing with errno=13 (EACCESS)
You wasn't properly setting the permission of the semaphore... it's a (sort of) file. Note that once you crete it with the wrong permissions, it stays there and it won't be possible to create it again with the same name (until you reboot the system). You can see them with: ls -l /dev/shm, and eventually just remove them with rm.
You was requesting O_EXCL, that is, exclusive access to one process, that's not what you want. See man 2 open.
the name of the semaphore must begin with /, see man sem_overview
Here is the revised code, some comments in-line:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#include <errno.h>
#define READ 0
#define WRITE 1
#define SEM1_NAME "/semaph_1a"
#define SEM2_NAME "/semaph_2a"
void handler(int sig) {
printf("process 1 is busy\n");
}
void codeprocess1(int pd[]) {
int i = 0;
int numgenerated;
// each process must open the handle to the same named semaphore.
// they cannot share a local memory address.
sem_t *my_sem = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
// the seed for the two children must be different or they will be generating the same
// sequence of random numbers.
srand(3333);
while(i == 0) {
signal(SIGUSR1, handler);
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
void codeprocess2(int pd[]){
int i = 0;
int numgenerated;
sem_t *my_sem = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
srand(1111);
while(i == 0) {
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
// O_EXCL removed
// the mode flag must be set to 0777 for example, not "1".
// return value check added
sem_t *sem1 = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (sem1==SEM_FAILED) {
printf("semaphore sem1 creation failed, errno=%d\n", errno);
exit(1);
}
sem_t *sem2 = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (sem2==SEM_FAILED) {
printf("semaphore sem2 creation failed, errno=%d\n", errno);
exit(1);
}
if (pipe(pipe1) < 0 ) {
exit(1);
}
if (pipe(pipe2) < 0) {
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1);
break;
default:
pid2= fork();
switch( pid2) {
case -1:
exit(1);
case 0:
codeprocess2(pipe2);
break;
default:
// 100, not 1000
while (sum != 100) {
// all the "close()" calls are commented out
// close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
// close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
// sum must not be incremented
sum = numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
There is really a lot going on in your question.
As posted in the answer #Sigismondo, you are confusing multithreading with multiprocess programming. They have different method of communications.
To oversimplify threads share the same memory, so a thread can see for example values of global variables such as semaphores mutex and so on: if a thread modifies it, the other thread will be affected.
In multiprocessing when you fork(), a new process is generated with its own memory space. Right after the fork() variable values are almost the same (apart pid, ppid and so on) but they are in a different memory space: if you have a code block executed by only one process, modifying it will not affect the variables (the semaphores in your program) of the other process.
In your case: first of all if the children process do the same stuff (i.e. generate a random number) why do you have to different functions? Can't you do something like:
#include<stdlib.h>
int generateRand()
{
n = rand() % 100 + 1; //should be random in [1, 100]
}
HANDLING SIGNALS
Process P1 must handle the SIGINT interrupt signal. In particular, at
the arrival of this signal P1 must display the warning message "P1
process busy!". The program is terminated by the parent P process when
it verifies that the sum of the numbers, which it has received from
the child processes, assumes the value 100.
This is really unclear, in my opinion. The parent should catch the SIGINT signal. What should the children do? From what you say it seems they shouldn't catch that signal. In this case you must take a look at signal masks: basically you have to block the signal in the parent, the call the fork()s and then put back the original mask. Now you should go deeper but somehting like this (here)
sigset_t *parent_mask, *child_mask
//get the current mask
if (int res = sigprocmask (0, NULL, child_mask)<0)
printf("some error\n");
//make the mask block the signal
if (int res = sigaddset(child_mask, SIGINT)<0)
printf("some error in sigaddset \n");
// block the signal with the new mask
if (int res = sigprocmask (SIG_SETMASK, child_mask, parent_mask)<0)
printf("some error\n");
//do your forks: children will inherit the current mask and will not catch SIGINT
...
fork()
...
fork()
....
//set back the original mask so the parent catches SIGINT
if (int res = sigprocmask (SIG_SETMASK, parent_mask, NULL)<0)
printf("some error\n");
This answer of mine, although for multithreading should be a little clearer.
SIGNAL HANDLER
Why are you registering the signal handler in codeprocess1(int pd[])? I don't get it at all. And why SIGUSR1?
You should do it in the parent (before or after the fork()s shouldn't change since the signal is blocked for children: it depends if you want to have the user exit the program before starting the forks() or not: in the first case register the signal handler after the fork() otherwise put it at the beginning of main(). In both case you should do:
signal(SIGINT, handler);
Now the core to your program: to communicate your program you can use pipe() in a blocking way together with file descriptors: check here.
You need two file descriptors (one per child process and close the end (read/write) not used by the process).
Consider a single child process:
int p = fork();
int fd1[2]; //file descriptor for child1
int fd2[2]; //file descriptor for child2
if (p>0)//parent
{
close(fd1[1]);//close writing end
int n;
read(fd1[0], &n, sizeof(n));
//you might to call the other fork here and redo the same stuff
int p2 = fork();
if (p2>0)
{
close(fd2[1]);//close writing end
int n2;
read(fd2[0], &n2, sizeof(n2));
sum = n2+n1
if (sum==100 && exit = 1)
{
kill(p, SIGKILL);
kill(p2, SIGKILL);
}
}
}
else if(p==0)//child
{
close(fd1[0]);//close read end
int rand_n = generateRand();//or whaterver the name
wrote(fd1[1], &rand_n, sizeof(rand_n));
}
The exit condition is both based on the value of the sum (100) and the fact that CTRL+C has been pressed. The former is obvious in the code above. For the latter you can declare a global variable (I used exit) that if 0 CTRL+C has not been pressed, if 1 it has. This value is checked in the exit condition of the code above. Your handler will be responsible to write this variable:
//global variable here
int exit = 0;
void handler(int signo)
{
print("Parent busy doing stuff\n");
exit =1;
}
Note one thing exit is written by the parent since it is written ONLY in the handler which is called only by the parent and it is read in the part of the code executed only by the parent: the the children read its value it will be always 0 for them.
Being your question too general I tried to give some hints: there might be errors in my code since I haven't tried. You should study your own. If you will provide a minimal working example I will try to help.
I am trying to make a simple semaphore example in C in which, having two while loops, will produce this outcome without threads, using two diferrent processes :
abcd
abcd
abcd
abcd
Since I cannot use pthreads, I tried to make the common signal() and wait() methods but for some reasons, I get an error in the wakeup call inside my signal method.
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
wait(sem_t *s)
{
s=s-1;
if (s<0)
block(); // add process to queue
}
signal(sem_t *s)
{
s=s+1;
if (s<=0)
wakeup(p); // remove process p from queue
}
init(sem_t *s , int v)
{
s=v;
}
void main(void)
{
int i;
// place semaphore in shared memory
sem_t *child_sem = mmap(NULL,sizeof(*child_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
sem_t *parent_sem = mmap(NULL,sizeof(*parent_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
init(child_sem, 1); // create child semaphore
init(parent_sem, 1); // create parent semaphore
if (fork())
{
for (i = 0; i < 10; i++)
{
if (wait(child_sem) < 0)
perror("sem_wait");
printf("ab");
if (signal(parent_sem) < 0)
perror("sem_post");
sleep(1); // required to maintain thread order
}
}
else
{
for (i = 0; i < 10; i++)
{ // parent starts waiting
if (wait(parent_sem) < 0)
perror("sem_wait");
printf("cd\n");
if (signal(child_sem) < 0)
perror("sem_post");
}
}
}
Output:
[Error] In function 'signal':
[Error] 'p' undeclared (first use in this function)
The thing is that how could I enter a process p inside the wakeup call?
Should I use a pid=fork() inside a method?
Should I use an extra argument in signal method but what would it be like? pid p ?
If I remove the p argument from wakeup, then variables like PROT_READ become undeclared for some reason.
P.S. The code is from this site.
I will not write the the whole thing but here is a better way to solve this.
Use 2 semaphores.
Run the first process when semaphore number 1 is high
Run the second process when semaphore number 2 is high
At the starting of the critical section of 1st process, make 2nd semaphore low so that the resource can not be used by the 2nd process
At the end of the critical section of the 1st process, make the 2nd semaphore = 1 and 1st semaphore = 0
Do exactly opposite for the second process, i.e., stating sem1 = 0, ending sem1 = 1, sem2 = 0.
This may solve the problem. Never use signal use sigaction instead.
I need to create a c file that takes in two arguments WAIT, and TIME.
The code should first fork() a child process which does work for W seconds and then exits. The parent process should wait on the child, but for T seconds maximum.
After T seconds of waiting, the parent process should stop waiting and print the the message "Timed out after T seconds.", and exit.
On the other hand, if the child terminates before the timeout, the parent should print the message "Child done." and exit.
I want to try and use the alarm() function to do this but I am stuck on how exactly.
#include <stdio.h>
int int main(int argc, char const *argv[])
{
int W = atoi(argv[1]);
int T = atoi(argv[2]);
pid_t pid = fork();
if (pid ==0){
sleep(W);
}
else{
alarm(T);
//REST OF CODE HERE
}
return 0;
}
I do not have much because I am trying to wrap my head around how to make the parent wait on the child for the given number of seconds.
Your help is appreciated.
I think what you're looking for is SIGCHLD ...this is a signal sent to the parent when a child changes status. There is a system call expressly designed to wait for this signal, appropriately called wait. There are 4 status changes that can trigger the signal, and the wait manpage documents how to check for them:
The child terminates normally
The child was terminated by a signal
The child was stopped by a signal
The child was continued by a signal
wait will block the parent until it receives a signal--either SIGCHLD or another unignored signal. This means your strategy of using alarm should work perfectly (however, you should note that the default action for SIGALRM is to terminate the program, so if that's not what you want, you'll need to change it):
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int W;
int T;
int status;
pid_t pid;
if(argc != 3) return 1;
W = atoi(argv[1]);
T = atoi(argv[2]);
pid = fork();
if(pid == 0)
{
sleep(W);
}
else
{
alarm(T);
if(wait() == -1)
{
/*
This will not actually run unless you override
the default action for SIGALRM
*/
}
else
{
/*Child changed state*/
/*Check how with WIF... macros*/
}
}
return 0;
}
You have one other option that may be a bit more work, but you might want to explore it. There is another system call named sigtimedwait which can wait for a set of signals (including SIGCHLD) with a timeout.