My code should be executing the start_hydrogen and start_carbon functions several times but only outputs to the console from execution of one thread and then the program hangs. I think I may be incorrectly starting my threads. I am new to C so let me know if additional information is needed. Note that the this line is reached output is printed.
#include "main.h"
void *start_hydrogen(void *);//executes hydrogen.c
void *start_carbon(void *);//executes carbon.c
struct threadInfo {
int threadId;
};
struct threadInfo hydrogenIDs[NUM_H];
struct threadInfo carbonIDs[NUM_C];
int main() {
int semid, shmid;//semaphore memory id, shared memory id
unsigned short seminit[NUM_SEMS];//used to initialize semaphores
struct common *shared;//pointer to shared data structure
union semun semctlarg;//used to initialize semaphores
pthread_t hydrogen[NUM_H];
pthread_t carbon[NUM_C];
pthread_attr_t attr;
void *exit_status;
//Creating a set of attributes to send to the threads
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, IPC_CREAT|0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
printf("THE PROGRAM IS STARTING\n\n");
seminit[MUTEX] = 1;//initialize mutex semaphore count to 1
seminit[SH] = 0;//initialize hyrdrogen semaphore count to 0
seminit[SC] = 0;//initialize carbon semaphore count to 0
semctlarg.array = seminit;//set control array
//apply initialization
if ((semctl(semid, NUM_SEMS, SETALL, semctlarg)) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, IPC_CREAT|0777)) < 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);
}
//initialize shared data structure variables
shared->waiting_H = 0;
shared->waiting_C = 0;
int retVal;//used to check return value of fork()
// spawn 20 Hydrogens
for (int i=0; i<NUM_H; i++) {
// if ((retVal = fork()) == 0) {
// hydrogen();
// fflush(stdout);
// printf("New Hydrogen process created\n");
// fflush(stdout);
// } else if (retVal < 0) {
// perror("fork");
// exit(EXIT_FAILURE);
// }
hydrogenIDs[i].threadId = i;
retVal = pthread_create(&hydrogen[i], &attr, start_hydrogen, (void*) &hydrogenIDs[i]);
if (retVal != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
printf("this line reached\n");
// spawn 5 Carbons
for (int i=0; i<NUM_C; i++) {
// if ((retVal = fork()) == 0) {
// carbon();
// fflush(stdout);
// printf("New Hydrogen process created\n");
// fflush(stdout);
// } else if (retVal < 0) {
// perror("fork");
// exit(EXIT_FAILURE);
// }
carbonIDs[i].threadId = i;
retVal = pthread_create(&carbon[i], &attr, start_carbon, (void*) &carbonIDs[i]);
if (retVal != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
//wait for all car processes to finish
// for (int i = 0; i < 25; ++i) {
// if (wait(0) < 0) {
// perror("wait");
// exit(EXIT_FAILURE);
// }
// }
//Wait for all the threads to finish
for(int i = 0; i < NUM_C; i++)
{
pthread_join(carbon[i], &exit_status);
}
for(int i = 0; i < NUM_H; i++)
{
pthread_join(hydrogen[i], &exit_status);
}
printf("All atoms have crossed!\n");
//delete semaphores
if (semctl(semid, NUM_SEMS, IPC_RMID, 0) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
//delete shared memory
if (shmctl(shmid, IPC_RMID, 0) < 0) {
perror("shmctl");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
Original start_carbon() and start_hydrogen() functions
void *start_carbon(void* arg) {
execl("carbon", "carbon", 0);
perror("execl");
exit(EXIT_FAILURE);//if exec returns there was an error
}
void *start_hydrogen(void* arg) {
execl("hydrogen", "hydrogen", 0);
perror("execl");
exit(EXIT_FAILURE);//if exec returns there was an error
}
Modified start_hydrogen() and start_carbon() functions
After receiving feedback about the inappropriateness of using execl(), I changed the start_hydrogen() and start_carbon() functions to:
void *start_hydrogen(void* arg) {
struct common *shared;//pointer to shared data structure
int semid, shmid;//semaphore memory id, shared memory id
int pid = getpid();
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, 0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, 0777)) < 0) {
perror("shmget");
exit(EXIT_FAILURE);
}
//get pointer to shared data structure
if ((shared = (struct common *)shmat(shmid, 0, 0)) < 0) {
perror("shmat");
exit(EXIT_FAILURE);
}
// acquire lock on mutex before accessing shared memory
semWait(semid, MUTEX);
fflush(stdout);
printf("Hydrogen atom, pid %d, arrives at barrier\n", pid);
printf("Currently %d Hydrogens and %d Carbons waiting\n", shared->waiting_H + 1, shared->waiting_C);
fflush(stdout);
// if enough C and H is waiting, continue past barrier
if (shared->waiting_H >= 3
&& shared->waiting_C >= 1) {
// release 3 H
for (int i=0; i < 3; i++) {
semSignal(semid, SH);
}
shared->waiting_H -= 3;
semSignal(semid, SC); // release 1 C
shared->waiting_C -= 1;
fflush(stdout);
printf("\nHello from %d, 1 CH4 molecule has xed the barrier\n\n", pid);
fflush(stdout);
// release lock on mutex
semSignal(semid, MUTEX);
} else {
// not enough C or H is waiting, so wait at barrier
shared->waiting_H += 1;
// relaese lock on mutex
semSignal(semid, MUTEX);
semWait(semid, SH);
}
pthread_exit(NULL);
}
void *start_carbon(void* arg) {
struct common *shared;//pointer to shared data structure
int semid, shmid;//semaphore memory id, shared memory id
int pid = getpid();
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, 0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, 0777)) < 0) {
perror("shmget");
exit(EXIT_FAILURE);
}
//get pointer to shared data structure
if ((shared = (struct common *)shmat(shmid, 0, 0)) < 0) {
perror("shmat");
exit(EXIT_FAILURE);
}
// acquire lock on mutex before accessing shared memory
semWait(semid, MUTEX);
fflush(stdout);
printf("Hydrogen atom, pid %d, arrives at barrier\n", pid);
printf("Currently %d Hydrogens and %d Carbons waiting\n", shared->waiting_H + 1, shared->waiting_C);
fflush(stdout);
// if enough C and H is waiting, continue past barrier
if (shared->waiting_H >= 3
&& shared->waiting_C >= 1) {
// release 3 H
for (int i=0; i < 3; i++) {
semSignal(semid, SH);
}
shared->waiting_H -= 3;
semSignal(semid, SC); // release 1 C
shared->waiting_C -= 1;
fflush(stdout);
printf("\nHello from %d, 1 CH4 molecule has xed the barrier\n\n", pid);
fflush(stdout);
// release lock on mutex
semSignal(semid, MUTEX);
} else {
// not enough C or H is waiting, so wait at barrier
shared->waiting_H += 1;
// relaese lock on mutex
semSignal(semid, MUTEX);
semWait(semid, SH);
}
pthread_exit(NULL);
}
From the man page for execl(),
The exec() family of functions replaces the current process image with a new process image.
and
The exec() functions only return if an error has occurred.
If you want to use execl() to call external programs, you should fork() the parent process first to allow the parent process to continue running. Note in that case, the threads really won't do what you want.
Related
I have the following program:
#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100
void ChildProcess(void);
void ParentProcess(void);
void main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
void ChildProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf(" This line is from child, value = %d\n", i);
printf(" *** Child process is done ***\n");
}
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
}
I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:
Create and initialize the shared memory in the parent.
Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
Fork from the parent to the child.
If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.
Expected output
What I did in the ParentProcess function is the following:
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
int localVar = 0;
int* p = (int*) malloc(2);
pid_t childPID = fork();
*p = 0;
if (childPID >= 0)
{
printf("\nChild process has started\n");
if (childPID == 0)
{
localVar++;
globalVar++;
printf("Child process has found the following data %d,", *p);
*p = 70;
printf( " %d,", *p);
*p = 66;
printf(" %d,", *p);
*p = 51;
printf(" %d,", *p);
*p = 90;
printf(" %d in shared memory\n",*p);
printf("Child is existing\n\n");
}
}
}
And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?
If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance
It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)
So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here
How to use shared memory with Linux in C
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
void *create_shared_memory(size_t size)
{
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
int main()
{
// Allocate 4 ints
void *shmem = create_shared_memory(sizeof(int)*4);
if( shmem == NULL ){
fprintf(stderr, "Failed to create shared memory\n");
return -1;
}
// Initialize 4 ints
((int*)shmem)[0] = 10;
((int*)shmem)[1] = 100;
((int*)shmem)[2] = 1000;
((int*)shmem)[3] = 10000;
int pid = fork();
if (pid == 0)
{
// Print 4 ints in child
printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
printf("Child end\n");
}
else
{
printf("Parent waiting for child ends...\n");
waitpid(pid, NULL, 0);
printf("Parent ends\n");
}
int ret = munmap(shmem, sizeof(int)*4);
if( ret != 0 ){
fprintf(stderr, "Failed to unmap shared memory\n");
return -1;
}
return 0;
}
I've written a small piece of c code which you might find helpful:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define NUM_INTS 5
int main(int argc, char *argv[])
{
key_t key = (key_t) 123456;
int shmgetrc, semgetrc;
struct shmid_ds ds;
int *shared_values;
int i;
struct sembuf sops[2];
int semid;
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
/* create SHM segment */
shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
if (shmgetrc < 0) {
perror("shmget failed...");
exit(1);
}
/* retrieve the address of the segment */
shared_values = (int *) shmat(shmgetrc, NULL, 0);
/* create a semaphore */
semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
if (semgetrc < 0) {
perror("semget failed...");
exit(1);
}
/* lock the semaphore */
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* fill it with values */
for (i = 0; i < NUM_INTS; ++i) {
shared_values[i] = i;
}
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* here something else could happen */
sleep(60);
/* lock the semaphore */
sops[0].sem_op = 0;
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* print values */
for (i = 0; i < NUM_INTS; ++i) {
printf("%d ", shared_values[i]);
}
printf("\n");
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* remove the semaphore */
if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
perror("semctl failed ...");
exit(1);
}
/* remove shm segment again */
if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
perror("shmctl failed ...");
exit(1);
}
exit(0);
}
It was not my intention to write the most beautiful code ever written, just an example that shows:
how to create a shm segment
how to retrieve the address and to use it
how to remove it
Additionally, I've used a semaphore to protect the access.
Contrary to the other answer, I've used the ipc interface, not mmap().
I make program which exec 2 times this code. 2 process enter to semaphore and stuck(HERE comment). Why it happen and how to fix it?
sem_t *sem = sem_open(SEM_NAME, O_RDWR);
if (sem == SEM_FAILED) {
perror("sem_open(3) failed");
exit(EXIT_FAILURE);
}
int j = atoi(argv[1]);
int i;
for (i = 0; i < 2; i++) {
printf("%i\n",getpid() );
//HERE!!!!!
if (sem_wait(sem) < 0) {
perror("sem_wait(3) failed on child");}
printf("PID %ld acquired semaphore\n", (long) getpid());
if (sem_post(sem) < 0) {
perror("sem_post(3) error on child");}
printf("wysz\n");
sleep(1);
}
semcl(sem);
return 0;
You should create the semaphore using this
sem_open(SEM_NAME, O_RDWR,0777, 1);
to set the starting value of the semaphore to 1.
The program consists of 2 parts (i was asked to use pipe):
A. manager - that creates processes that will help him calculate how many instances of a particular char are in the file.
B. Count - Calculates how many instances there are in the file and returns the pipe to the manager.
Moreover, In each program I changed the behavior of SIGPIPE, and changed the behavior I desired.
in the manager.c:
for(i = 0; i < len_sym; i++){
...
if (pipe(pipe_fds + (2 * i)) == -1) {
perror("ERROR : Failed creating pipe");
exit(EXIT_FAILURE);
}
if ((curr_child = fork()) == 0){ //son
dup2(pipe_fds[2*i + 1], STDOUT_FILENO);
close(pipe_fds[2*i + 1]);
close(pipe_fds[2*i + 0]);
execvp(child_args[0], child_args);
}
else { //parent
if (curr_child == -1){
exit(EXIT_FAILURE);
}
close(pipe_fds[2*i + 1]); // close writerfd
child_pids[i] = curr_child;
printf("%d son created with pid %d\n", i + 1, child_pids[i]);
// if (i == 1) {
// kill(curr_child, SIGPIPE);
// }
}
}
for(i = 0; i < len_sym; i++){
curr_child = waitpid(child_pids[i], &exit_code, 0);
printf("exit code %d\n", exit_code);
printf("child pid %d\n", curr_child);
if (curr_child == -1 || 256 == exit_code) {
exit(EXIT_FAILURE);
}
if (WIFEXITED(exit_code)) {
int bytes_read;
while ((bytes_read = read(pipe_fds[i*2 + 0], buff, BUFF_SIZE)) > 0) {
buff[bytes_read] = '\0';
printf("%s", buff);
}
if (bytes_read == -1) {
perror("ERROR : Failed reading from fifo");
close(pipe_fds[i*2 + 0]);
exit(EXIT_FAILURE);
}
close(pipe_fds[i*2 + 0]);
child_pids[i] = 0;
}
}
handling SIGPIPE in manager.c
void my_signal_handler(int signum) {
switch (signum) {
case SIGPIPE:
printf("SIGPIPE for Manager process %d. Leaving\n", getpid());
for (int i = 0; i < len_sym; i++) {
if ((child_pids != NULL) && child_pids[i]) {
kill(child_pids[i], SIGTERM);
}
}
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void register_signal_handlin() {
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = my_signal_handler;
if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
}
in the count.c:
for (j = 0; j < file_length; j++){
if (*temp++ == c){
counter++;
}
}
sleep(10);
if (argc > 4){
sprintf(buff, "Process %d finishes. Symbol %c. Instances %d.\n", getpid(), c, counter);
int buff_len = strlen(buff);
int bytes_written;
while ((bytes_written = write(writerfd, p, buff_len)) > 0) {
p += bytes_written;
buff_len -= bytes_written;
}
if (bytes_written == -1) {
perror("PROCESS ERROR : Failed writing to fifo");
close(writerfd);
return EXIT_FAILURE;
}
close(writerfd);
}
handling SIGPIPE in count.c
void my_signal_handler(int signum) {
switch (signum) {
case SIGPIPE:
printf("SIGPIPE for process %d. Symbol %c. Counter %d.\n", getpid(), c, counter);
exit(EXIT_FAILURE);
case SIGTERM:
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void register_signal_handling() {
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = my_signal_handler;
if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
if (0 != sigaction(SIGTERM, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
}
So in fact I run the manger program, and at the same time opens a new terminal, and from it sends kill -13 to a particular process.
the problems:
In the manager I get an exit code of 256. Why?
The WIFSIGNALED flag does not turn on, although I have sent a signal to the process.
The return from the waitpid function is not -1, but the process number I sent kill -13 from the second terminal.
I tried to send kill to one of the children from the manager and for some reason he activates the signal handler of the manager rather than the child's signal handler.
I am in the process of learning OS, so I will be happy for any help.
A memory location is shared by three processes. Each process independently tries to increase the content of the shared memory location from 1 to a certain value by increments of one. Process 1 has target of 100000, Process 2’s target is 200000 and the goal of 3 is 300000. When the program terminates, therefore, the shared memory variable will have a total of 600000 (i.e. this value will be output by whichever of the three processes finishes last). I am to protect the critical section using semaphores.
My problem is that I am having issues with the SETVAL for each process when initializing the semaphore. It keeps printing "Error detected in SETVAL" even though I have it set to 1. Correct sample output as well as my code is shown below:
Sample output
From Process 1: counter = 100000.
From Process 2: counter = 300000.
From Process 3: counter = 600000.
Child with ID 2412 has just exited.
Child with ID 2411 has just exited.
Child with ID 2413 has just exited.
End of Simulation.
/*ass1*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#define SEMKEY ((key_t) 400L)
// number of semaphores being created
#define NSEMS 2
/* change the key number */
#define SHMKEY ((key_t) 7890)
typedef struct
{
int value;
} shared_mem;
shared_mem *total;
//structure
int sem_id, sem_id2;
typedef union{
int val;
struct semid_ds *buf;
ushort *array;
} semunion;
static struct sembuf OP = {0,-1,0};
static struct sembuf OV = {0,1,0};
struct sembuf *P =&OP;
struct sembuf *V =&OV;
//function
int Pop()
{
int status;
status = semop(sem_id, P,1);
return status;
}
int Vop()
{
int status;
status = semop(sem_id, V,1);
return status;
}
/*----------------------------------------------------------------------*
* This function increases the value of shared variable "total"
* by one with target of 100000
*----------------------------------------------------------------------*/
void process1 ()
{
int k = 0;
while (k < 100000)
{
Pop();
if (total->value < 600000) {
total->value = total->value + 1;
}
Vop();
k++;
}
printf ("From process1 total = %d\n", total->value);
}
/*----------------------------------------------------------------------*
* This function increases the vlaue of shared memory variable "total"
* by one with a target 200000
*----------------------------------------------------------------------*/
void process2 ()
{
int k = 0;
while (k < 200000)
{
Pop();
if (total->value < 600000) {
total->value = total->value + 1;
}
Vop();
k++;
}
printf ("From process2 total = %d\n", total->value);
}
/*----------------------------------------------------------------------*
* This function increases the vlaue of shared memory variable "total"
* by one with a target 300000
*----------------------------------------------------------------------*/
void process3 ()
{
int k = 0;
while (k < 300000)
{
Pop();
if (total->value < 600000) {
total->value = total->value + 1;
}
Vop();
k++;
}
printf ("From process3 total = %d\n", total->value);
}
/*----------------------------------------------------------------------*
* MAIN()
*----------------------------------------------------------------------*/
int main()
{
int shmid;
int pid1;
int pid2;
int pid3;
int ID;
int status;
char *shmadd;
shmadd = (char *) 0;
//semaphores
int semnum = 0;
int value, value1;
semunion semctl_arg;
semctl_arg.val =1;
/* Create semaphores */
sem_id = semget(SEMKEY, NSEMS, IPC_CREAT | 0666);
if(sem_id < 0)
printf("creating semaphore");
sem_id2 = semget(SEMKEY, NSEMS, IPC_CREAT | 0666);
if(sem_id2 < 0)
printf("creating semaphore");
/* Initialize semaphore */
value1 =semctl(sem_id, semnum, SETVAL, semctl_arg);
value =semctl(sem_id, semnum, GETVAL, semctl_arg);
if (value < 1)
printf("Eror detected in SETVAL");
/* Create and connect to a shared memory segmentt*/
if ((shmid = shmget (SHMKEY, sizeof(int), IPC_CREAT | 0666)) < 0)
{
perror ("shmget");
exit (1);
}
if ((total = (shared_mem *) shmat (shmid, shmadd, 0)) == (shared_mem *) -1)
{
perror ("shmat");
exit (0);
}
total->value = 0;
if ((pid1 = fork()) == 0)
process1();
if ((pid1 != 0) && (pid2 = fork()) == 0)
process2();
if ((pid1 != 0 ) && (pid2 != 0) && (pid3 = fork()) == 0 )
process3();
waitpid(pid1, NULL, 0 );
waitpid(pid2, NULL, 0 );
waitpid(pid3, NULL, 0 );
if ((pid1 != 0) && (pid2 != 0) && (pid3 != 0))
{
waitpid(pid1);
printf("Child with ID %d has just exited.\n", pid1);
waitpid(pid2);
printf("Child with ID %d has just exited.\n", pid2);
waitpid(pid3);
printf("Child with ID %d has just exited.\n", pid3);
if ((shmctl (shmid, IPC_RMID, (struct shmid_ds *) 0)) == -1)
{
perror ("shmctl");
exit (-1);
}
printf ("\t\t End of Program\n");
/* De-allocate semaphore */
semctl_arg.val = 0;
status =semctl(sem_id, 0, IPC_RMID, semctl_arg);
if( status < 0)
printf("Error in removing the semaphore.\n");
}
}
Some basics - IPCs last longer than the process so as has been mentioned use ipcs and ipcrm to delete pre-existing ipcs between runs. Make sure you delete the ipcs after execution
waitpid(pid1, NULL, 0 );
waitpid(pid2, NULL, 0 );
waitpid(pid3, NULL, 0 );
This section is going to be run for the children - they probably shouldn't.
total->value = total->value + 1;
Is not IPC safe, so different results may occur (proc1 may overwrite proc2's increment).
I can't exit or terminate children processes sending a signal.
Could you please tell me what I'm doing wrong in this code:
//###################################### INVERTER.C (main)
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>
#include "timeprofiler.h"
#include "ppmtools.h"
//Global vars:
int shmids[4], shmPixelId, *total_lines, *processed_lines, *next_line, *buf_vars;
//To share unnamed semaphores between processes, they must be allocated in a shared memory.
mem_struct *sh_mm;
//unnamed semaphores
sem_t *mutex1, *mutex2, *mutex3, *sem_remaining_lines;
//struct that will hold the image in shared memory
image_struct *image;
pid_t *workersPID;
header *h;
int main(int argc, char *argv[]) {
int i, j, k, cur = 0, id;
pixel *row;
double start, stop, startms, stopms;
if (argc < 3) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm output_filename.ppm\"\n");
return -1;
}
//BLOCK ALL SIGNAL
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
//start timer
start = getCurrentTimeMicro();
startms = getCurrentTimeMili();
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
printf("Opening output file [%s]\n", argv[2]);
FILE *fpout = fopen(argv[2], "w");
if (fpout == NULL) {
printf("Could not open output file\n");
return -1;
}
printf("Getting header\n");
h = getImageHeader(fpin);
if (h == NULL) {
printf("Error getting header from file\n");
return -1;
}
printf("Got file Header: %s - %u x %u - %u\n", h->type, h->width, h->height, h->depth);
printf("Saving header to output file\n");
if (writeImageHeader(h, fpout) == -1) {
printf("Could not write to output file\n");
return -1;
}
init();
printf("After init...\n");
//alloc mem space for one row (width * size of one pixel struct)
row = (pixel *) malloc(h->width * sizeof (pixel));
printf("Starting work\n");
for (i = 0; i < h->height; i++) {
printf("Reading row... \n");
if (getImageRow(h->width, row, fpin) == -1) {
printf("Error while reading row\n");
}
printf("Got row %d || \n", (i + 1));
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
image->pixel_data[j].red = row[k].red;
image->pixel_data[j].blue = row[k].blue;
image->pixel_data[j].green = row[k].green;
}
cur += h->width;
}
/*Creates workers*/
workersPID = (pid_t*) malloc(sizeof (pid_t) *((NUM_WORKERS)));
for (i = 0; i < NUM_WORKERS; i++) {
id = fork();
if (id == -1) {
printf("Error creating worker no %d\n", i);
return (EXIT_FAILURE);
} else if (id == 0) {
workersPID[i] = getpid();
printf("Launching son with pid %d\n", getpid());
worker(i);
}
}
cur = 0;
sem_wait(mutex2);
/*Writes the invert image on the output file*/
for (i = 0; i < h->height; i++) {
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
row[k].red = image->pixel_data[j].red;
row[k].blue = image->pixel_data[j].blue;
row[k].green = image->pixel_data[j].green;
}
cur += h->width;
printf("Saving row... \n");
if (writeRow(h->width, row, fpout) == -1) {
printf("Error while writing row\n");
}
printf("Done\n");
}
printf("Cleaning up...\n");
//clean up row
free(row);
//clean up header
free(h);
printf("Closing file pointers.\n");
fclose(fpin);
fclose(fpout);
//stop timer
stop = getCurrentTimeMicro();
stopms = getCurrentTimeMili();
for (i = 0; i < NUM_WORKERS; i++) {
if (workersPID[i]) {
kill(workersPID[i], SIGTERM);
waitpid(workersPID[i], NULL, 0);
}
}
terminate();
printTimeElapsed(start, stop, "microseconds");
printTimeElapsed(startms, stopms, "miliseconds");
printf("Done!\n");
return 0;
}
void init() {
//create shared memory to hold the source image:
if ((shmids[0] = shmget(IPC_PRIVATE, sizeof (image_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate image struct failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image = (image_struct*) shmat(shmids[0], NULL, 0);
//shared memory to allocate the pointer to pointer pixel_data
if ((shmids[1] = shmget(IPC_PRIVATE, h->width * h->height * sizeof (pixel), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate pixel_data array failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image->pixel_data = (pixel*) shmat(shmids[1], NULL, 0);
/*Shared Memory segment for 3 integers*/
if ((shmids[2] = shmget(IPC_PRIVATE, 3 * sizeof (int), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate the 3 integers failed. Errno returned; %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
buf_vars = (int*) shmat(shmids[2], NULL, 0);
total_lines = &buf_vars[0];
processed_lines = &buf_vars[1];
next_line = &buf_vars[2];
*processed_lines = *next_line = 0;
*total_lines = h->height;
if ((shmids[3] = shmget(IPC_PRIVATE, sizeof (mem_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate mem_Struct for semaphores failed. Errno returned %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sh_mm = (mem_struct*) shmat(shmids[3], NULL, 0);
if (sem_init(&sh_mm->mutex1, 1, 1) == -1) {
printf("Error initializing semaphore mutex1.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex1 = &sh_mm->mutex1;
if (sem_init(&sh_mm->mutex2, 1, 0) == -1) {
printf("Error initializing semaphore mutex2.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex2 = &sh_mm->mutex2;
if (sem_init(&sh_mm->mutex3, 1, 1) == -1) {
printf("Error initializing semaphore mutex3.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex3 = &sh_mm->mutex3;
if (sem_init(&sh_mm->sem_remaining_lines, 1, h->height) == -1) {
printf("Error initializing semaphore sem_remaining_lines.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sem_remaining_lines = &sh_mm->sem_remaining_lines;
}
/*Worker process*/
void worker(int id) {
int i, k, cur = 0;
pixel *row;
//Block all signals, except SIGINT and SIGKILL which are handled
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigdelset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
while (sem_wait(sem_remaining_lines)!= -1) { //if there are still lines to read, go on
sem_wait(mutex3);
cur = *next_line; //current image's line
*next_line += h->width; //refreshs line for the next worker
sem_post(mutex3);
row = (pixel *) malloc(h->width * sizeof (pixel));
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
row[k].red = image->pixel_data[i].red;
row[k].blue = image->pixel_data[i].blue;
row[k].green = image->pixel_data[i].green;
}
//printf("% - Inverting row... \n",id);
invertRow(h->width, row); //invert
//printf("Done || \n");
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
image->pixel_data[i].red = row[k].red;
image->pixel_data[i].blue = row[k].blue;
image->pixel_data[i].green = row[k].green;
}
sem_wait(mutex1);
*processed_lines += 1; //increases the number of inverted lines
if (*processed_lines == *total_lines) { //check if it reaches last line
sem_post(mutex2); //if so, wakes the master telling that is ready
}
sem_post(mutex1);
}
//printf("Son %d is exiting\n",id);
exit(0);
}
void handle_signal(int signum) {
if(signum == SIGINT)
signal(SIGINT, handle_signal);
else
signal(SIGTERM, handle_signal);
exit(0);
}
void terminate() {
int i;
//close semaphores
sem_destroy(mutex1);
sem_destroy(mutex2);
sem_destroy(mutex3);
sem_destroy(sem_remaining_lines);
//cleans up shared memory = removes shared memory segments
for (i = 0; i < 4; i++) {
shmctl(shmids[i], IPC_RMID, NULL);
}
}
I'm gonna leave the explanation of the assignment (that has already finished btw)here:
1 page pdf
Your worker threads have SIGTERM blocked (because it was blocked in main, and sigprocmask doesn't remove signals from the blocked set unless explicitly told to do so)
You may want to do something like this in the worker instead:
sigemptyset(&block_ctrlc);
sigaddset(&block_ctrlc, SIGINT);
sigaddset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_UNBLOCK, &block_ctrlc, NULL);
Alternately, call sigprocmask with SIG_SETMASK.