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];
}
Related
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;
}
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;
}
I'm implementing a solution to a problem that uses shared memory, but somehow, my code seems to "freeze" between a print statement and an if statement.
Here's the relevant code snippet:
#include "ch_problem_headers.h"
int main(int argc, char *argv[])
{
int semid, shmid;
int i;
int waiting_C, waiting_H = 0; // shared
int c_pid,h_pid;
time_t t;
// There should be three semaphores: S for when to pass the molecule on,
// SC for the carbon waiting, and SH for the hydrogen waitin
unsigned short seminit[NUM_SEMS];
struct common *shared;
union semun semctlarg;
srand((unsigned)time(&t));
if((semid = semget(IPC_PRIVATE, NUM_SEMS, IPC_CREAT|0777)) < 0)
{
perror("semget");
exit(EXIT_FAILURE);
}
// Initialize semaphores
seminit[S_SEM] = 1;
seminit[SC_SEM] = 0;
seminit[SH_SEM] = 0;
semctlarg.array = seminit;
// Apply initialization
if((semctl(semid, NUM_SEMS, SETALL, semctlarg)) < 0)
{
perror("semctl");
exit(EXIT_FAILURE);
}
// Get shared memory id
if((shmid = shmget(IPC_PRIVATE, 1*K, IPC_CREAT|IPC_EXCL|0660)) < 0)
{
perror("shmget");
exit(EXIT_FAILURE);
}
// Retrieve pointer to shared data structure
if((shared = (struct common *)shmat(shmid, 0, 0)) < 0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
shared->waiting_C = 0;
shared->waiting_H = 0;
printf("ready to fork\n");
// fork process C
c_pid = fork();
printf("c_pid is %d\n", c_pid);
if(c_pid == 0)
{
printf("I'm process C!/n");
// wait on S
semWait(semid, S_SEM);
// if waiting_H >= 4
if(shared->waiting_H >= 4)
{
// signal SH four times
for(i = 0; i < 4; i++)
{
semSignal(semid, SH_SEM);
printf("H");
}
// Decrement waiting_H by 4
shared->waiting_H -= 4;
// Signal S
semSignal(semid, S_SEM);
}
// Otherwise, increment waiting_C by 1
else
{
shared->waiting_C += 1;
// Signal S and wait for SC
semSignal(semid, S_SEM);
semWait(semid, SC_SEM);
}
}
else
{
printf("C's process id is %d\n", c_pid);
printf("ready to fork again\n");
// fork process H
h_pid = fork();
printf("Is h_pid zero? %d\n", (h_pid == 0));
if(h_pid == 0)
{
printf("I'm process H!/n");
// Wait on S
semWait(semid, S_SEM);
// If waiting_h >= 3
if(shared->waiting_H >= 3)
{
// Signal SH three times, decrement waiting_H by 3, signal SC, decrement
for(i = 0; i < 3; i++)
{
printf("H");
semSignal(semid, SH_SEM);
}
shared->waiting_H -=3;
semSignal(semid, SC_SEM);
shared->waiting_C -= 1;
semSignal(semid, S_SEM);
// waitng_C by 1, and signal S
}
// Otherwise, increment waiting_H by 1, signal S, and wait on SH
else
{
shared->waiting_H += 1;
semSignal(semid, S_SEM);
semWait(semid, SH_SEM);
}
}
else
{
printf("In the parent\n");
}
}
}
And the relevant header file:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define K 1024
#define NUM_SEMS 3
#define SEMKEY 77
#define SHMKEY 77
#define S_SEM 0
#define SH_SEM 1
#define SC_SEM 2
#define NUM_H 4
#define NUM_C 1
union semun
{
unsigned short *array;
};
struct common
{
int waiting_C;
int waiting_H;
};
void semWait(int semid, int semaphore)
{
struct sembuf psembuf;
psembuf.sem_op = -1;
psembuf.sem_flg = 0;
psembuf.sem_num = semaphore;
semop(semid, &psembuf, 1);
return;
}
void semSignal(int semid, int semaphore)
{
struct sembuf vsembuf;
vsembuf.sem_op = 1;
vsembuf.sem_flg = 0;
vsembuf.sem_num = semaphore;
semop(semid, &vsembuf, 1);
return;
}
The program output when run is as follows:
Parent output (correct) :
ready to fork
c_pid is 2977
C's process ID is 2977
ready to fork again
Is h_pid zero? 0
In the parent
Child output:
Is h_pid zero? 1
c_pid is 0
I tried running the program in valgrind, and the program simply halted after the child output. I'm confused as to how this is possible, as the program seems to simply stop between the c_pid print statement and the if(c_pid == 0) statement.
Does anyone have any idea why this might be? Thanks so much.
I'm currently being introduced to the concept of threading programs, and have been given an assignment to simulate a stockmarket using threads and semaphores. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
#define NUM_WRITERS 5
#define NUM_READERS 5
#define STOCKLIST_SIZE 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t stop_writers;
typedef struct
{ int readers;
int slots[STOCKLIST_SIZE];
} mem_structure;
int id[NUM_READERS + NUM_WRITERS];
mem_structure *stocklist;
pthread_t thr[NUM_WRITERS + NUM_READERS];
void init(){
sem_init(&stop_writers, 0, 1);
}
void cleanup(int signo) // clean up resources by pressing Ctrl-C
{ sem_destroy(&stop_writers);
printf("Closing...\n");
exit(0);
}
void write_stock(int n_writer)
{
int stock = (int)(rand()%STOCKLIST_SIZE);
int stock_value = 1 + (int)(100.0 * rand()/(RAND_MAX + 1.0));
stocklist->slots[stock] = stock_value;
fprintf(stderr, "Stock %d updated by BROKER %d to %d\n", stock, n_writer, stock_value);
}
void* writer(void* id){
int my_id = *((int*) id);
int i = my_id;
while (1)
{
pthread_mutex_lock(&mutex);
sem_wait(&stop_writers);
write_stock(i);
pthread_mutex_unlock(&mutex);
sem_post(&stop_writers);
sleep(1);
++i;
}
}
void read_stock(int pos, int n_reader){
fprintf(stderr, "Stock %d read by client %d = %d.\n", pos, n_reader, stocklist->slots[pos]);
}
void* reader(void* id){
int my_id = *((int*) id);
int i = my_id;
while (1)
{ sem_wait(&stop_writers);
read_stock((int)(rand()%STOCKLIST_SIZE), i);
sem_post(&stop_writers);
sleep(1 + (int) (3.0 * rand() / (RAND_MAX + 1.0)));
++i;
}
}
void monitor() // main process monitors the reception of Ctrl-C
{
struct sigaction act;
act.sa_handler = cleanup;
act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1))
perror("Failed to set SIGINT to handle Ctrl-C");
while(1){
sleep(5);
printf("Still working...\n");
}
exit(0);
}
int main(void)
{ int i, j;
init();
for (i = 0; i < NUM_WRITERS; ++i){
id[i] = i;
pthread_create(&thr[i], NULL, writer, &id[i]);}
for (j = i; j < NUM_READERS; ++j){
id[j] = j;
pthread_create(&thr[j], NULL, reader, &id[j]);}
stocklist->readers = 0;
pthread_exit(NULL);
monitor();
return 0;
}
This is giving me a segmentation fault pretty much as soon as main() begins, with the creation of a thread... Since it's not code that I've created from root, I'm having trouble backtracing the error and fixing it - it would be great if there was someone who could take a look and maybe give me some hints
Thank you!
EDIT
Fixed the problem, thanks to your help :)
I initialized stocklist on init(),
void init(){
sem_init(&stop_writers, 0, 1);
stocklist = (mem_structure*)malloc(sizeof(mem_structure));
}
And changed the second cicle in main(),
for (j = i; j < NUM_READERS+NUM_WRITERS; ++j){
id[j] = j;
pthread_create(&thr[j], NULL, reader, &id[j]);}
Thanks
Here's what I did to track down the problem:
gcc -g program.c -lpthread
gdb a.out
run
Output:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7feeb70 (LWP 23060)]
0x08048834 in write_stock (n_writer=0) at program.c:44
44 stocklist->slots[stock] = stock_value;
Looks like the problem is here:
stocklist->slots[stock] = stock_value;
This will probably require some looking into, but my question is very simple:
Why is numPassenger always 0 in the parentHandler2() function?
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/time.h>
#include <math.h>
int getRand()
{
return (rand() % 5001);
}
//////////GLOBAL//////////
const int CAPACITY = 100;
const int MEMSIZE = 1024;
char* sharedmem;
pid_t pid;
int numPassenger;
int numTram;
//////////GLOBAL//////////
//handles SIGALRM, generates passengers, sends SIGUSR1
void parentHandler1()
{
numPassenger = getRand();
sprintf(sharedmem, "%d", numPassenger);
kill(getpid(), SIGUSR1);
}
//handles SIGUSR1, calculates number of trams needed, sends SIGUSR2
void childHandler()
{
double n = atoi(sharedmem);
numTram = (ceil(n/100));
sprintf(sharedmem, "%d", numTram);
kill(pid, SIGUSR2);
}
//outputs
void parentHandler2()
{
int n = atoi(sharedmem);
printf("Passengers: %d, Trams: %d\n", numPassenger, n);
}
int main (int argc, char* argv[])
{
srand(time(0));
key_t key;
int shmemaddr;
//shared memory
key=ftok(argv[0],1);
shmemaddr=shmget(key,MEMSIZE,IPC_CREAT|S_IRUSR|S_IWUSR);
sharedmem = shmat(shmemaddr,NULL,0);
pid = fork();
if ( pid > 0 )
{
//timer
struct itimerval timer;
timer.it_value.tv_sec = 3;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 3;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer, NULL);
signal(SIGALRM, parentHandler1);
signal(SIGUSR1, childHandler);
}
else if ( pid == 0 )
{
signal(SIGUSR2, parentHandler2);
}
//not so busy waiting
while(1) sleep(1);
return 0;
}
https://gist.github.com/4299915
Fork creates a new copy of the current process. Global variables aren't shared between processes. The only memory that is shared between your two processes is the memory returned by shmget. The value of numPassenger is never set in the child process.