MPI Receive much slower when called in child thread rather than parent - c

In the code below I try to receive an MPI message having two active threads. Passing 0 as command line argument the parent thread will use MPI_Recv and the child will send it. Passing 1 will cause the child to use MPI_Recv and the parent to send. I see huge differences in the times that I get between the 2 case as the size of the message becomes bigger. Do you have any idea why this could be happening?
#include <stdio.h>
#include <mpi.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdlib.h>
#include <pthread.h>
pthread_t _comm_thread;
#define KILO 1024
#define MILLION 1000000
#define START_TIMER(timer) { gettimeofday(&(timer), NULL); }
#define STOP_TIMER(timer) { gettimeofday(&(timer), NULL); }
#define TIME_DIFF(timer1, timer2, total) { \
long long sec_diff = 0; \
long long usec_diff = 0; \
sec_diff = (timer2).tv_sec - (timer1).tv_sec; \
usec_diff = (timer2).tv_usec - (timer1).tv_usec; \
(total) += (sec_diff * MILLION) + usec_diff; \
}
short done_flag = 0;
short finished = 0;
int num_messages = 500;
int payload_sizes[] = {1, 2, 4 , 8, 16,32,64,128,256,512,1024,2*KILO,4*KILO,8*KILO,16*KILO,32*KILO,64*KILO,128*KILO,256*KILO,512*KILO,KILO*KILO};
// int payload_sizes[] = {KILO*KILO};
int num_payload_sizes = 21;
int loops=0;
void* receive(void* args){
int my_proc;
MPI_Comm_rank(MPI_COMM_WORLD,&my_proc);
long long total;
struct timeval start, stop;
if( my_proc==0 ){
int i;
char buffer [KILO*KILO];
for(i=0;i<num_payload_sizes;++i)
{
done_flag = 0;
total = 0;
int j;
START_TIMER(start)
for(j=0;j<num_messages;++j)
{
MPI_Send(buffer,payload_sizes[i],MPI_BYTE,1,0,MPI_COMM_WORLD);
}
STOP_TIMER(stop)
TIME_DIFF(start,stop,total)
printf("Payload size: %d : time : %lld usec\n",payload_sizes[i],(total)/num_messages);
}
}
else{
int cnt=0;
char* buffer;
while(1){
MPI_Status stat;
int size;
MPI_Probe(MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&stat);
MPI_Get_count(&stat,MPI_BYTE,&size);
buffer = (char *)malloc(size);
MPI_Recv(buffer,size,MPI_BYTE,0,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
cnt++;
if(cnt == num_messages){
loops++;
cnt =0;
}
if(loops == num_payload_sizes){
free(buffer);
break;
}
free(buffer);
}
}
pthread_exit(0);
}
void * nothing(void *args){
pthread_exit(0);
}
int main(int argc, char* argv[]){
int provided;
if(argc != 2){
printf("Please pass as argument 0 to run the MPI_Recv in parent or 1 to run it in the child\n");
return -1;
}
int choice = atoi(argv[1]);
MPI_Init_thread( NULL, NULL, MPI_THREAD_SERIALIZED,&provided);
if( provided!= MPI_THREAD_SERIALIZED){
printf("MPI_THREAD_SERIALIZED is not provided\n");
return -1;
}
if( choice == 0){
pthread_create( &_comm_thread, NULL, nothing, NULL);
receive(NULL);
}else if(choice == 1){
pthread_create( &_comm_thread, NULL, receive, NULL);
}else{
printf("Must choose 0 or 1\n");
return -1;
}
pthread_join(_comm_thread,NULL);
MPI_Finalize();
return 0;
}

Related

Can't I send 2 messages with different key with message queue with child-parent IPC in C?

Trying to send 2 different integers with 2 different keys in same function. but lower one doesn't actually work and only show -1 value.
Child is sending 2 messages, and parent receives it.
and parent's printf receives it with msgrcv, and should show its pid and cpu_burst value.
Tried compiling with gcc, but child() still skips while(sunstatus) and go direct to printf and returns 0.
This is my code.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include "msg_cm.h"
#include "runq.h"
#include "waitq.h"
#include "cidq.h"
void timer_handler(int signum) {
int temp = runq[0];
putwtq(temp);
rmvrnq();
}
int child(int key, int quant){
int cpid = getpid();
srand(cpid);
int cpu_burst = rand() % 100 + 6;
int io_burst = rand() % 100 + 1;
msg_sndr(key, cpid);
msg_sndr(cpid, cpu_burst);
int runstatus = 1;
int onoffchk = 0;
while(runstatus) {
if (msg_rcvr(getpid()) > 0) {
onoffchk = 1 - onoffchk;
}
if (onoffchk == 1) {
cpu_burst = cpu_burst - quant;
}
}
printf("Child process terminated.\n");
msg_sndr(5678, 3);
return 0;
}
int main() {
int temp = 500000;
int cnt = 1;
int pid;
int quantum = 5;
int count = 9;
int comp[10];
while(temp > 0) {
msg_rcvr(1234);
temp = temp -1;
}
printf("Parent running: %d\n", getpid());
for (int i = 0; i < 10; i++) {
pid = fork();
if(pid == 0) {
break;
}
else if (pid > 0) {
printf("Child process : %d created.\n", pid);
}
else {
printf("fork() failed!!!");
return -1;
}
}
if(pid == 0) {
child(1234, quantum);
}
else {
int tick = 1;
int end = 10;
struct sigaction sigac;
struct itimerval timer;
struct itimerval stoptimer;
sigac.sa_handler = timer_handler;
sigaction(SIGALRM, &sigac, NULL);
timer.it_value.tv_sec = quantum;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = quantum;
timer.it_interval.tv_usec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
while(end > 1){
if (msg_rcvr(5678) > 0) {
end--;
setitimer(ITIMER_REAL, &stoptimer, NULL);
setitimer(ITIMER_REAL, &timer, NULL);
}
if (msg_exist(1234) != 2) {
putrnq(msg_rcvr(1234));
}
if (runq[0] == -1) {
printf("%d\tidle\n",tick);
}
else {
printf("%d\tProcess: %d running...\tCPU burst: %d", tick, runq[0], msg_rcvr(runq[0]));
}
tick++;
sleep(1);
}
printf("All childs are terminated.\n");
}
return 0;
}
msg_cm.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgdata {
long int msg_type;
int text;
}message;
int msg_sndr(int key, int num) {
int msgid;
struct msgdata message;
char buf[20];
msgid = msgget((key_t)key, 0666 | IPC_CREAT);
if (msgid == -1) {
printf("error while creating msg q!!!");
return -1;
}
message.msg_type = 1;
message.text = num;
if (msgsnd(msgid, (void *)&message, sizeof(message), 0) == -1) {
printf("msg not sent!!!");
return -1;
}
}
int msg_rcvr(int key) {
int msgid;
struct msgdata message;
long int msg_to_rec = 0;
msgid = msgget((key_t)key, 0666| IPC_CREAT);
if (msgrcv(msgid, (void *)&message, sizeof(message), msg_to_rec, 0 | IPC_NOWAIT) > 0) {
return message.text;
}
else {
return -1;
}
msgctl(msgid, IPC_RMID, 0);
}
int msg_exist(int key) {
int msgid;
msgid = msgid = msgget((key_t)key, 0666| IPC_CREAT);
struct msqid_ds buf;
int rc = msgctl(msgid, IPC_STAT, &buf);
unsigned int msg = (unsigned int)(buf.msg_qnum);
rc = msgctl(msgid, IPC_STAT, &buf);
msg = (uint)(buf.msg_qnum);
if (msg > 0) {
return 1;
}
else {
return 2;
}
}
*all of idq.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cburstq[20];
int ccount = 0;
void putidq(int num) {
cburstq[ccount] = num;
ccount++;
}
int rmvidq() {
int tmp = cburstq[0];
for (int tmpnm = 0; tmpnm < ccount; tmpnm++){
cburstq[tmpnm] = cburstq[tmpnm + 1];
}
ccount--;
return tmp;
}

In C, I want to access one array in two separate processes [duplicate]

This question already has answers here:
How to use shared memory with Linux in C
(5 answers)
Closed 4 years ago.
This is essentially what I want to do, but the outputs are junk data. What are some of the different options I have for making the child's array visible from inside the parent process?
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int foo[3]; //initialize array
pid_t pid;
pid = fork(); //create child thread
if (pid == 0) { //child:
foo[0] = 0; foo[1] = 1; foo[2] = 2; //populate array
}
else { //parent:
wait(NULL); //wait for child to finish
printf("%d %d %d", foo[0], foo[1], foo[2]); //print contents of array
}
return 0;
}
Using mmap you can create a shared memory block in your parent process. This is a basic example removing error checking for brevity.
You want to sure the proper protections and flags are set for your needs. Then hand off the address returned by mmap to your child process.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define LIMIT_MAP 5
void child_worker(void *map)
{
int map_value = -1;
int idx = 0;
while (map_value != LIMIT_MAP) {
map_value = *((int *) map + (idx * sizeof(int)));
printf("Map value: %d\n", map_value);
idx++;
sleep(2);
}
}
int main(int argc, char *argv[])
{
printf("Starting Parent Process...\n");
long page_size = sysconf(_SC_PAGESIZE);
void *memory_map = mmap(0, page_size, PROT_WRITE | PROT_READ,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
printf("Memory map created: <%p>\n", memory_map);
pid_t pid = fork();
if (pid == 0) {
sleep(1);
printf("Starting child process\n");
child_worker(memory_map);
printf("Exiting child process...\n");
return 0;
} else {
printf("Continuing in parent process\n");
int set_values[5] = { 1, 2, 3, 4, 5 };
for (int i=0; i < 5; i++) {
printf("Setting value: %d\n", set_values[i]);
*((int *) memory_map + (sizeof(int) * i)) = set_values[i];
sleep(1);
}
waitpid(pid, NULL, 0);
printf("Child process is finished!\n");
}
return 0;
}
If fork isn't a requirement and your platform allows for it, pthread is one option. Depending on how your array is being operated on, create a thread pool passing each worker thread a copy of your array.
This is a contrived example but maybe you can pull something from it:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define THREAD_COUNT 3
#define ITER_LIMIT 7
struct worker_params {
int idx;
int max;
bool done;
double *data;
double condition;
};
void *worker(void *arg)
{
struct worker_params *wp = (struct worker_params *) arg;
int count = 0;
while ( 1 ) {
wp->data[wp->idx] = drand48();
if (wp->max == count)
wp->done = true;
sleep(1);
count++;
}
return NULL;
}
int main(int argc, char *argv[])
{
double data[THREAD_COUNT] = { 0.0 };
pthread_t worker_1, worker_2, worker_3;
pthread_t worker_threads[] = { worker_1, worker_2, worker_3 };
struct worker_params wps[] = {
{ .idx=0, .condition=0.1, .data=data, .done=0 },
{ .idx=1, .condition=0.2, .data=data, .done=0 },
{ .idx=2, .condition=0.3, .data=data, .done=0},
};
for (int i=0; i < THREAD_COUNT; i++) {
wps[i].max = (rand() % ITER_LIMIT) + 2;
pthread_create(&worker_threads[i], NULL, worker, (void *) &wps[i]);
}
// Continue on main execution thread
int running = 1;
while ( running ) {
for (int i=0; i < THREAD_COUNT; i++) {
if (wps[i].done) {
printf("Limit hit in worker <%d>\n", i + 1);
running = 0;
break;
}
printf("Data in worker <%d> :: %g\n", i + 1, wps[i].data[i]);
}
sleep(1);
}
return 0;
}

Issue with Threading in C for Linux

Here is what I need to do:
Write a pthread program that takes an integer command line argument n,
spawns n threads that will each generate a random numbers between -100
and 100, and then computes and prints out the sum of these random
numbers. Each thread needs to print out the random number it
generates.
Here is what I have:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
int randomNum=0;
int randomSum=0;
void *randomNumberGenerator(void *id){
int *myid = (int *)id;
randomNum = rand()% 201 + (-100);
printf("%d\n", randomNum);
randomSum+=randomNum;
}
int main (int argc , char *argv[]){
int command;
char *strNumThreads = NULL;
int i;
while((command = getopt(argc, argv, "n:"))!=-1){
if(command == 'n'){
strNumThreads = optarg;
break;
}
}
int numThreads = atoi(strNumThreads);
pthread_t thread;
int newThread;
for(i = 0; i<numThreads; i++){
srand(time(NULL));
pthread_create(&thread, NULL, randomNumberGenerator, (void*)i);
}
pthread_exit(NULL);
printf("%d\n" , randomSum);
return 0;
}
For some reason randomSum is not getting printed.
randomNum is a variable that is shared among all threads, so you need a mutex
when you access the variable, because randomSum+=randomNum; is not an atomic
operation. The current process might get interrupted and another process is
scheduled which changes both variables. When the interrupted process resumes, it
will overwrite randomNum and you end up with garbage.
Also you have to wait for all threads to finish until you print the sum. For
that you have to execute pthread_wait.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
// can be a global variable
int randomSum=0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *randomNumberGenerator(void *id){
int randomNum=0; // does not need to be a global variable
randomNum = rand()% 201 + (-100);
printf("%d\n", randomNum);
pthread_mutex_lock(&mutex);
randomSum+=randomNum;
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}
int main (int argc , char *argv[]){
int command;
char *strNumThreads = NULL;
int i;
while((command = getopt(argc, argv, "n:"))!=-1){
if(command == 'n'){
strNumThreads = optarg;
break;
}
}
// initializing the randomizer
srand(time(NULL));
int numThreads = atoi(strNumThreads);
if(numThreads == 0)
{
fprintf(stderr, "Invalid number of threads\n");
return 1;
}
pthread_t threads[numThreads];
for(i = 0; i<numThreads; i++){
pthread_create(threads + i, NULL, randomNumberGenerator, NULL);
}
for(i = 0; i < numThreads; ++i)
pthread_join(threads[i], NULL);
printf("%d\n" , randomSum);
return 0;
}
You really need to learn how to use the libraries you are using. pthread_exit
must be used by the threads to tell the system "I'm finished", calling it in the
main thread makes no sense.
pthread_create(&thread, NULL, randomNumberGenerator, (void*)i);
I consider this an uggly hack, what you should do is create an array with the
ids of the threads and pass every thread a pointer to its id, like this:
int ids[numThreads];
for(i = 0; i<numThreads; i++){
ids[i] = i;
pthread_create(&thread, NULL, randomNumberGenerator, ids+i);
}
and in the thread you can do
void *randomNumberGenerator(void *idp) {
int *id = idp;
printf("My thread id is %d\n", *id);
...
pthread_exit(NULL);
}
And if your worker threads are just calculating a value, you can use
pthread_exit to return that value back to the main thread. For example:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
struct thdata {
int id;
int random;
};
void *randomNumberGenerator(void *data) {
struct thdata *ret = data;
ret->random = rand()% 201 + (-100);
printf("thread with id %d: random %d\n", ret->id, ret->random);
pthread_exit(data);
}
int main (int argc , char *argv[]){
int i;
// initializing the randomizer
srand(time(NULL));
int numThreads = 5;
if(numThreads == 0)
{
fprintf(stderr, "Invalid number of threads\n");
return 1;
}
pthread_t threads[numThreads];
struct thdata data[numThreads];
for(i = 0; i<numThreads; i++){
data[i].id = i;
pthread_create(threads + i, NULL, randomNumberGenerator, data+i);
}
int randomSum = 0;
for(i = 0; i < numThreads; ++i)
{
struct thdata *data;
pthread_join(threads[i], (void**) &data);
randomSum += data->random;
}
printf("The sum of the random values is: %d\n" , randomSum);
return 0;
}
Which gives me the output (for 5 threads):
thread with id 0: random 72
thread with id 4: random -94
thread with id 1: random 1
thread with id 2: random -74
thread with id 3: random 42
The sum of the random values is: -53
You currently have a data race in place, because you have multiple threads accessing randomSum concurrently. Here's a solution, with comments, using Mutexes to solve the problem.
Note how using a struct to hold the sum and it's mutex allows us to get rid of all globals.
As a plus, I replaced your random generator with a proper one on POSIX systems. Note that your multiple calls to srand() are wrong, and cause less randomicity. You should only ever call srand() once, to generate the seed.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <pthread.h>
static bool HAS_URANDOM = true; // Global
unsigned int random_uint() {
unsigned int r_uint;
// Try to open the random generator device
FILE *f = fopen("/dev/urandom", "r");
if (f == NULL) {
if (HAS_URANDOM) {
// Warn that urandom isn't working, but fallthrough to rand()
printf("---- Failed loading random generator device /dev/urandom. Defaulting to rand().\n");
srand((unsigned int) time(NULL));
HAS_URANDOM = false;
}
r_uint = (unsigned int) rand();
} else {
// If we have urandom, just read from it and cast to uint
fread(&r_uint, sizeof(r_uint), 1, f);
fclose(f);
}
return r_uint;
}
// Inclusive range
// https://stackoverflow.com/a/17554531/2080712
unsigned int generate_uint(unsigned int lower, unsigned int upper) {
if (upper - lower == UINT_MAX) {
fprintf(stderr, "Invalid bounds on generate_int().\n");
exit(EXIT_FAILURE);
}
unsigned int r_uint;
const unsigned int range = 1 + (upper - lower);
if (range == 0) {
fprintf(stderr, "Invalid range!\n---- upper=%d\n---- lower=%d\n---- range=%d\n", upper, lower, range);
exit(EXIT_FAILURE);
}
const unsigned int buckets = UINT_MAX / range;
const unsigned int limit = buckets * range;
/* Create equal size buckets all in a row, then fire randomly towards
* the buckets until you land in one of them. All buckets are equally
* likely. If you land off the end of the line of buckets, try again. */
do {
r_uint = random_uint();
} while (r_uint >= limit);
unsigned int res = lower + (r_uint / buckets);
return res;
}
typedef struct {
pthread_mutex_t lock; // Our lock to avoid data races
long sum; // The sum value
} sum_t;
// Thread function
void *do_sum(void *arg) {
sum_t *sum = (sum_t*)(arg); // Reinterpret the argument as sum_t
int val = generate_uint(0, 100) - 100; // Generate an integer in the range we want
pthread_mutex_lock(&sum->lock); // Lock the value
sum->sum += val; // Sum
pthread_mutex_unlock(&sum->lock); // Unlock the value
return NULL;
}
int main(int argc, char *argv[]) {
// Guarantee argument
if(argc != 2) {
printf("Please provide a number of threads.\n");
exit(EXIT_FAILURE);
}
// Get our thread count
long count = strtol(argv[1], NULL, 10);
// Allocate threads
pthread_t threads[count];
// Create & initialize sum structure
sum_t sum;
pthread_mutex_init(&(sum.lock), NULL);
sum.sum = 0;
// Run sum threads
for (long i = 0; i < count; ++i) {
pthread_create(&(threads[i]), NULL, do_sum, &sum);
}
// Wait until they have finished
for (long i = 0; i < count; ++i) {
pthread_join(threads[i], NULL);
}
// Destroy the mutex lock
pthread_mutex_destroy(&(sum.lock));
// Print result
printf("%ld\n", sum.sum);
return 0;
}

Exit a for loop if not input is entered after some time

So I want a method to controlling the amount of time the input prompt will wait for the user to enter something.
For example in the following code:
#include <stdio.h>
int main(void){
int i, value;
for (i=0;i<10;i++){
scanf(" %d", &value);
}
}
How can I make the program to break the for loop if the user doesn't enter any input after 5 seconds?
You can implement what you want using select (monitor stdin for some time to check if the input is available for reading), fgets (safely read input data to the buffer) and strtol (convert the buffer string to the long integer if possible).
Sample code is given below (check man pages e.g. to extend error handling):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
fd_set rfds;
struct timeval tv;
int i, val, retval;
char *endptr, buff[255];
for (i=0;i<10;i++){
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
if (retval == -1){
perror("select()");
exit(EXIT_FAILURE);
}
else if (retval){
/* FD_ISSET(0, &rfds) is true so input is available now. */
/* Read data from stdin using fgets. */
fgets(buff, sizeof(buff), stdin);
/* Convert data stored in the buffer to long int. */
errno = 0;
val = strtol(buff, &endptr, 10);
/* First, check for various possible errors. */
if (errno != 0 && val == 0) {
perror("strtol()");
exit(EXIT_FAILURE);
}
if (endptr == buff) {
fprintf(stderr, "No digits were found.\n");
exit(EXIT_FAILURE);
}
/* If we got here, strtol successfully parsed a number. */
printf("%d was read from stdin.\n", val);
}
else{
printf("No data within five seconds.\n");
break;
}
}
exit(EXIT_SUCCESS);
}
Here is a general purpose version of scanf, sync_scanf, witch should wait for seconds you choose or will return -2 as timeout:
int sync_scanf(time_t sec, const char *format, ...);
example:
#include <stdio.h>
#include <stdarg.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int sync_scanf(time_t sec, const char *format, ...);
int main(int argc, char **argv) {
int i;
int value;
int ret;
for (i = 0 ; i < 10 ; i++ ) {
ret = sync_scanf(3, "%d", &value);
if( ret > 0 ) {
printf("OK %d\n", value);
} else if( ret == -2 ) {
printf("3 seconds passed and you typed nothing!\n");
break;
} else {
printf("No enough arguments\n");
break;
}
}
return 0;
}
int sync_scanf(time_t sec, const char *format, ...) {
int re;
va_list arg;
fd_set readfds;
struct timeval timeout = {0};
timeout.tv_sec = sec;
FD_ZERO(&readfds);
FD_SET(0, &readfds);
re = select(1, &readfds, NULL, NULL, &timeout);
if( re == -1 ) {
perror("Error");
return -1;
}
else if( re == 0 ) {
return -2;
}
va_start(arg, format);
re = vfscanf(stdin, format, arg);
va_end(arg);
return re;
}
demo:
$ gcc -Wall sample.c
$ ./a.out
232
OK 232
3 seconds passed and you typed nothing!
$ ./a.out
32
OK 32
fewf
No enough arguments
$
It works as scanf but you pass the timeout first in seconds:
int sync_scanf(time_t sec, const char *format, ...);
It returns:
-1 on failure.
-2 on timeout.
Other than that it returns as scanf would does.
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
int flag;
static sigjmp_buf jmpbuf;
static void sig_arm(int signo)
{
if(flag == -1)
return;
else if(flag == 0)
siglongjmp(jmpbuf,1);
}
int main(void){
int i, value;
signal(SIGALRM,sig_arm);
for (i=0;i<10;i++){
if(sigsetjmp(jmpbuf,0) == 0)
{
flag = 0;
alarm(5);
scanf(" %d", &value);
flag = 1;
}
if(flag == 0) // 5 second out
break;
}
flag = -1;
alarm(0);
}

No signals sent (POSIX and C)

I have written the code below, and I want the following:
In every 5 secs the parent gets a random int and puts into into the shared mem, then sends a signal to its child.
The child calculates how many trams are needed to carry that amount of passengers (as you can see there are defs for TRAM_CAP etc) and then the child puts the new tram count into the shared mem.
Finally, after it is informed by a signal, the parent prints the count of passengers and trams.
My problem is that no signals are sent but I dont know why.
I searched and googled million times but nothing... The timer is working but nothing else (just the first "tram amount calculation")
Btw this is the second C code I have written in my life :S so I am a newbie.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "fcntl.h"
#include "errno.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "unistd.h"
#include <sys/time.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <math.h>
#define MEM_KEY 2003
#define INTERVAL 2
#define NEW_STAT SIGUSR1
#define NEW_TRAM_CNT SIGUSR2
#define MAX_PASSENGER 1000
#define TRAM_CAP 60
// "slots" in shared memory
#define PASS_CNT 0
#define TRAM_CNT 1
int get_pass_stat();
void handle_pass_stat_generation (int sig);
void handle_exit_func (int sig);
void set_pass_stat_generation();
void handle_new_tram_cnt_set(int sig);
void handle_new_stat_arrived(int sig);
void set_data(int which, int to);
int get_data(int which);
static pid_t ppid;
static pid_t chpid;
int main()
{
int shmid = shmget((key_t) MEM_KEY, sizeof(int) * 2, IPC_CREAT | 0666);
int* segptr = shmat(shmid, 0, 0);
segptr[PASS_CNT] = 0;
segptr[TRAM_CNT] = 0;
// seed for rand
srand((unsigned)time(NULL));
//
int pid=fork();
if(pid == 0) // child
{
signal(NEW_STAT, handle_new_stat_arrived);
while(1) sleep(30);
}else if(pid > 0) // parent
{
chpid = pid;
ppid = getpid();
signal(NEW_TRAM_CNT, handle_new_tram_cnt_set);
signal(SIGINT,handle_exit_func);
set_pass_stat_generation(pid);
while(1) sleep(30);
}else
{
perror("Fork error.");
exit(1);
};
return 0;
}
int get_pass_stat()
{
return rand() % MAX_PASSENGER + 1;
}
void handle_pass_stat_generation (int sig)
{
int st = get_pass_stat();
set_data(PASS_CNT, st);
kill( chpid, NEW_STAT );
printf("%i is the pass. cnt %i is the tram cnt. \n", st, get_data(TRAM_CNT));
// set_pass_stat_generation();
}
void handle_exit_func (int sig)
{
printf("\nBye Bye!!!\n");
exit(0);
}
void set_pass_stat_generation()
{
struct itimerval tval;
tval.it_interval.tv_sec = INTERVAL;
tval.it_interval.tv_usec = 0;
tval.it_value.tv_sec = INTERVAL; /* 5 seconds timer */
tval.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tval,0);
signal(SIGALRM, handle_pass_stat_generation); /* set the Alarm signal capture */
}
void handle_new_stat_arrived(int sig)
{
int tram_count = get_data(TRAM_CNT);
int passenger_count = get_data(PASS_CNT);
if( (TRAM_CAP * tram_count < passenger_count) ||
(TRAM_CAP * (tram_count-1) > passenger_count) ||
(passenger_count == 0) )
{
int new_cnt = (int) ceil((double)passenger_count / (double)TRAM_CAP);
set_data(TRAM_CNT, new_cnt);
kill( ppid, NEW_TRAM_CNT );
}
signal(NEW_STAT, handle_new_stat_arrived);
}
void handle_new_tram_cnt_set(int sig)
{
signal(NEW_TRAM_CNT,handle_new_tram_cnt_set);
}
void set_data(int which, int to)
{
int shmid = shmget((key_t) MEM_KEY, 0, 0);
int* segptr = shmat(shmid, 0, 0);
segptr[which] = to;
}
int get_data(int which)
{
int shmid = shmget((key_t) MEM_KEY, 0, 0);
int* segptr = shmat(shmid, 0, 0);
return segptr[which];
}

Resources