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).
Related
I have coded little program that uses shared memory that sends bytes around basicly.
The problem I have is, I think, that I'm getting stuck in the child process (it prints Process 2: 5000 and then nothing).
Can anyone help me? I'd really appreciate it!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main() {
int sem_id;
int shm_id;
key_t key = ftok("shared_memory", 1); // Create key shared memory
key_t keytwo = ftok("semaphore", 1); // Create key semaphore
shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666); // Create shared memory
sem_id = semget(keytwo, 1, IPC_CREAT | 0666); // Create Semaphore
if((shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666)) == -1){ // -1 indicates error
perror("semctl");
exit(1);
} else {
printf("Shared memory created with id: %d \n", shm_id);
}
if((sem_id = semget(keytwo, 1, IPC_CREAT | 0666)) == -1){ // -1 indicates error
perror("semctl");
exit(1);
} else {
printf("Sephamore created with id: %d \n", shm_id);
}
struct sembuf sem_lock = {0, -1, 0}; // Struct for semop to lock
struct sembuf sem_unlock = {0, 1, 0}; // Struct for semop to unlock
char *data = (char *)shmat(shm_id, NULL, 0); // Connect Shared-Memorys to Process
pid_t pid;
semctl(sem_id, 0, SETVAL, 1); //initialize the semaphore with value 1
if((semctl(sem_id, 0, SETVAL, 1)) == -1){ // -1 indicates error
perror("semctl");
exit(1);
} else {
printf("Sephamore initialized \n");
}
pid = fork();
if(pid < 0){
printf("Error");
return 1;
}
int p = 1;
int c = 1;
//16777216 = 1024 * 16384
char *message = (char *) malloc(16777216);
char *read = (char *) malloc(16777216);
for (int KiB = 1; KiB <= 16384; KiB *= 2) {
int bytes = KiB * 1024;
for(int i = 0; i < 1000; i++){
if (pid == 0) {
// Process 2:
semop(sem_id, &sem_lock, 1);
memcpy(read, data, bytes); //"read" data
//printf("%s \n", read) //print to check whether read worked
semop(sem_id, &sem_unlock, 1);
//print to check race condition
printf("Process 2 print: %d \n", p);
p++;
} else {
// Process 1:
for (int i = 0; i < bytes; ++i) {
message[i] = 'a';
}
semop(sem_id, &sem_lock, 1);
printf("%d", sem_id);
memcpy(data, message, bytes);
semop(sem_id, &sem_unlock, 1);
//print to check race condition
printf("Process 1 print: %d \n", c);
c++;
wait(NULL);
}
}
}
shmdt(data); // Remove shared-memory from process
shmctl(shm_id, IPC_RMID, NULL); // Delete shared memory
semctl(sem_id, 0, IPC_RMID); // Delete semaphore
return 0;
}
I was expecting the processes to alternate.
I have tried:
Place locks differently, Add locks, Remove locks, Remove unlocks, sleep(1).
I am not saying this is the reason for the failure, but you are not testing any return codes from these functions. Always test returns, especially if you are seeing problems and / or are new to calls
taking semctl as an example. looking here https://man7.org/linux/man-pages/man2/semctl.2.html you see that it returns a value indicating the result
so here
semctl(sem_id, 0, SETVAL, 1); //initialize the semaphore with value 1
you should do
if(semctl(sem_id, 0, SETVAL, 1) == -1){ // -1 indicates error
perror("semctl");
exit(1);
}
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 am trying to add the variable bank into shared memory to explore race conditions and process synchronization using semaphores. When I setup the variable in shared memory my program gives me segmentation fault:11. Can someone explain what I am doing wrong here and how I can go about fixing this? Thanks!
RACE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <semaphore.h>
int shmid;
int shmkey = 585858;
sem_t mutex; // semaphore global variable
struct Bank {
int balance[2];
};
struct Bank *bank;
// routine for thread execution
void* MakeTransactions() {
int i, j, tmp1, tmp2, rint;
double dummy;
// wait on semaphore
//sem_wait(&mutex);
for (i=0; i < 100; i++) {
rint = (rand()%30)-15;
if (((tmp1=bank->balance[0])+rint) >=0 &&
((tmp2=bank->balance[1])-rint)>=0) {
//sem_wait(&mutex);
bank->balance[0] = tmp1 + rint;
//sem_post(&mutex);
for (j=0; j < rint*100; j++) {
dummy=2.345*8.765/1.234; // spend time on purpose
}
//sem_wait(&mutex);
bank->balance[1] = tmp2 - rint;
//sem_post(&mutex);
}
}
// increment value of semaphore
//sem_post(&mutex);
return NULL;
}
int main(int argc, char **argv) {
int i;
void* voidptr = NULL;
// initialize semaphore
sem_init(&mutex, 0, 1);
// shared memory
//bank = mmap(NULL, sizeof(struct Bank), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
// create shared memory
shmid = shmget(shmkey, 1024, IPC_CREAT);
// attach to shared memory
bank = shmat(shmid, NULL, 0);
//check if bank is not NULL
bank->balance[0] = 100;
bank->balance[1] = 100;
pid_t pid;
srand(getpid());
printf("\nInit balances A:%d + B:%d ==> %d!",
bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]);
pid=fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid == 0) {
printf("\nChild computing ...");
MakeTransactions();
printf("\nChild process complete");
printf("\nLet's check the balances A:%d + B:%d ==> %d ?= 200",
bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]);
return 0;
}
else {
printf("\nParent computing...\n");
MakeTransactions();
wait(NULL);
printf("\nParent process complete\n");
printf("Let's check the balances A:%d + B:%d ==> %d ?= 200\n\n",
bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]);
return 0;
}
sem_destroy(&mutex);
// deattach shared memory pointer
shmdt(&bank,NULL);
//munmap(bank, sizeof(struct Bank));
return 0;
}
Okay the reason it gives you a segfault is because you're probably running this program as an unprivileged user. shmat requires privileges. If you are running it under linux you can do this:
sudo setcap cap_ipc_owner=ep ./myprog
to enable it to call shmat etc.
and then run it.
You would've found out about this if you had added a bit of error handling:
shmid = shmget(shmkey, 1024, IPC_CREAT);
if (shmid == -1 ) {
perror("shmget");
exit(errno);
}
// attach to shared memory
bank = shmat(shmid, NULL, 0);
if (bank == (void *)-1) {
perror("bank");
exit(errno);
}
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.
I have an assignment, and im beating my head against the wall. It is in C. I have a feeling im close to the solution, however I cant get the program to do whats required. I am changing the numbers and some small details, because most of the class is as stumped as I.
Requirements: Create 3 processes, the first one will increment a shared memory variable "total->value" from 1 to 10000, the second from 10000 to 12000, the third from 12000 to 14000
The process functions are labeled such (process1(), process2(), process3())
and the internals of those functions are as follows
process1()
{
int k = 0;
while (k < 10000)
{
k++;
total->value = total->value + 1;
}
printf("From process 1 = %d/n", total->value);
}
The second would be k < 2000 (because it only needs to increment the shared value 2000 more) and etc.
The main portion of the program is:
main()
{
int shmid;
int pid1;
int pid2;
int pid3;
int ID;
int status;
char *shmadd = (char *)0;
/* 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();
if ((pid1 != 0) && (pid2 != 0) && (pid3 != 0))
{
if ((shmctl(shmid, IPC_RMID, (struct shmid_ds *)0)) == -1)
{
perror("shmctl");
exit(-1);
}
printf("\t\t End of Program.\n");
}
}
What I need is for the first process to finish, before the 2nd starts. I tried inserting a wait(&status) after the process1() (or 2 or 3) calls and am at a loss. Any pointers? (no pun intended) =) there is more to implement, but I believe once I have this part I can handle the rest on my own. I have been intentionally vague in some regards, but I would like to finish this project and more importantly understand it and there are others who want a free lunch. I will provide anything else in the code that is required. Thank you in advance for your help
The output should appear
From process 1 = 10000
From process 2 = 12000
From process 3 = 14000
I believe that Celada's comment/guess on the requirements is correct. However, barring that, and at the risk of doing too much work, the following code fulfills your spec. The use of the gcc built-in __sync_fetch_and_add() is perhaps unnecessary.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
static struct {
int value;
} *total;
static void process1(void) {
int k = 0;
while (k < 10000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 1 = %d\n", total->value); //<-- not quite right: could be >10000
}
static void process2(void) {
int k = 0;
while (__sync_fetch_and_add(&total->value, 0) != 10000)
;
while (k < 2000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 2 = %d\n", total->value);
}
static void process3(void) {
int k = 0;
while (__sync_fetch_and_add(&total->value, 0) != 12000)
;
while (k < 2000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 3 = %d\n", total->value);
}
int main(void) {
int shmid;
int pid1;
int pid2;
int pid3;
int status;
/* Create and connect to a shared memory segment */
if ((shmid = shmget(1234, sizeof *total, IPC_CREAT|0666)) < 0) {
perror ("shmget");
exit (1);
}
if ((total = shmat(shmid, 0, 0)) == (void *)-1) {
perror("shmat");
exit (0);
}
total->value = 0; // not necessary in Linux if IPC_CREAT invoked
if (!(pid1 = fork()))
process1();
else if (!(pid2 = fork()))
process2();
else if (!(pid3 = fork()))
process3();
else {
wait(&status);
wait(&status);
wait(&status);
if ((shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0)) == -1) {
perror("shmctl");
exit (-1);
}
printf("\t\t End of Program.\n");
}
return 0;
}