Here's a simple example:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <signal.h>
#include <sys/shm.h>
#include <errno.h>
#include <time.h>
typedef union semun
{
int val;
struct semid_ds *buf;
ushort *array;
}semun;
int main(int argc, char *argv[]) {
int key = ftok("test.c", 1);
semun t;
int sem_id = semget(key, 1 , 0666 | IPC_CREAT | IPC_EXCL);
printf("%d", sem_id);
if(sem_id != -1){
printf("Creating a new semaphore...\n");
t.val = 1;
semctl(sem_id, 0, SETVAL, &t);
}
else if (errno == EEXIST) {
printf("Connecting...");
sem_id = semget(key, 1, 0);
}
else {
printf("LINUX Error");
exit(0);
}
struct sembuf P;
P.sem_num = 0;
P.sem_op = -1;
P.sem_flg = 0;
semop(sem_id, &P, 1);
printf("Hello\n");
semctl(sem_id, 0, IPC_RMID);
return 0;
}
The code bellow semop doesn't get printed out, yet I have an example of to me exactly the same code on the side which works. What could be wrong with this code? I've checked the semaphore array and emptied it before each run.
The problem was with the & sign in this line.
semctl(sem_id, 0, SETVAL, &t);
Related
I’m trying to use the system V semaphores, but I'm not able to control their value with semop, and so what they do. I should have three total processes that alternate with each other with semaphores that regulate the game turns. If anyone can help me with a practical example I would be very grateful.
PROCESS1
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#define KSEM 2292
#define KKSEM 9922
int main(int argc, char *argv[]){
struct sembuf x;
x.sem_num = 0;
x.sem_op = -1;
x.sem_flg = 0;
int idserver, idclient;
int val1 = 0, val2 = 0;
// declaration
idserver = semget (KSEM, 1, IPC_CREAT | IPC_EXCL | 0666);
idclient = semget (KKSEM, 1, IPC_CREAT | IPC_EXCL | 0666);
if (idserver <0){
perror("idserver: ");
_exit(1);
}
if (idclient <0){
perror("idclient: ");
_exit(1);
}
printf("hello1");
// intializing
semctl(idserver, 0, SETVAL, val1); //server set to 0
semctl(idclient, 0, SETVAL, val2); //client set to 0
printf("ciaoserver1");
int a;
a = semop (idserver, &x, 1);
printf("waiting for client...");
printf("VALUE SERVER: %i \n", a);
return 0;
}
PROCESS2
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#define KSEM 2292
#define KKSEM 9922
int main(int argc, char *argv[]){
struct sembuf x;
x.sem_num = 0;
x.sem_op = 1;
x.sem_flg = 0;
struct sembuf y;
y.sem_num = 0;
y.sem_op = 0;
y.sem_flg = 0;
struct sembuf z;
y.sem_num = 0;
y.sem_op = -2;
y.sem_flg = 0;
int idserver, idclient;
int val1 = 0, val2 = 0;
// declaration
idserver = semget (KSEM, 1, IPC_EXCL | 0666);
if(idserver < 0) {
perror("idserver: ");
_exit(1);
}
idclient = semget (KKSEM, 1, IPC_EXCL | 0666);
if(idclient<0){
perror("idclient: ");
_exit(1);
}
// initialize
semctl(idserver, 0, SETVAL, val1); //server set to 0
semctl(idclient, 0, SETVAL, val2); //client set to 0
printf("CLIENT1");
int a;
a = semop (idclient, &x, 1);
semop (idclient, &y, 1);
semop (idclient, &x, 1);
semop (idclient, &y, 1);
semop (idserver, &y, 1);
printf("VALUE CLIENT 1: %i", a);
return 0;
}
In fork child, if we modify a global variable, it will not get changed in the main program.
Is there a way to change a global variable in child fork?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int glob_var;
main (int ac, char **av)
{
int pid;
glob_var = 1;
if ((pid = fork()) == 0) {
/* child */
glob_var = 5;
}
else {
/* Error */
perror ("fork");
exit (1);
}
int status;
while (wait(&status) != pid) {
}
printf("%d\n",glob_var); // this will display 1 and not 5.
}
You can use shared memory (shm_open(), shm_unlink(), mmap(), etc.).
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static int *glob_var;
int main(void)
{
glob_var = mmap(NULL, sizeof *glob_var, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*glob_var = 1;
if (fork() == 0) {
*glob_var = 5;
exit(EXIT_SUCCESS);
} else {
wait(NULL);
printf("%d\n", *glob_var);
munmap(glob_var, sizeof *glob_var);
}
return 0;
}
Changing a global variable is not possible because the new created process (child)is having it's own address space.
So it's better to use shmget(),shmat() from POSIX api
Or You can use pthread , since pthreadsare sharing the globaldata and the changes in global variable is reflected in parent.
Then read some Pthreads tutorial.
Here is an alternative solution.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct
{
int id;
size_t size;
} shm_t;
shm_t *shm_new(size_t size)
{
shm_t *shm = calloc(1, sizeof *shm);
shm->size = size;
if ((shm->id = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0)
{
perror("shmget");
free(shm);
return NULL;
}
return shm;
}
void shm_write(shm_t *shm, void *data)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("write");
return;
}
memcpy(shm_data, data, shm->size);
shmdt(shm_data);
}
void shm_read(void *data, shm_t *shm)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("read");
return;
}
memcpy(data, shm_data, shm->size);
shmdt(shm_data);
}
void shm_del(shm_t *shm)
{
shmctl(shm->id, IPC_RMID, 0);
free(shm);
}
int main()
{
int var = 1;
shm_t *shm = shm_new(sizeof var);
int pid;
if ((pid = fork()) == 0)
{ /* child */
var = 5;
shm_write(shm, &var);
printf("child: %d\n", var);
return 0;
}
/* Wait for child to return */
int status;
while (wait(&status) != pid);
/* */
shm_read(&var, shm);
/* Parent is updated by child */
printf("parent: %d\n", var);
shm_del(shm);
return 0;
}
Build with:
$ gcc shm.c -o shm && ./shm
I have to create a program that synchronizes two processes each printing only a single letter so that whenever we observe the output of the program, the difference between the amount of "A" and "B" is no greater than 2.
So this would be accepted:
BAABBAABBABA
this wouldn't be because it prints 4 B's and only 2 A's:
ABBABB
So for starters i decided to use the POSIX semaphores.
I created two semaphores , giving them all the permissions using the sem_open
Then i created two child processes and for each child process i open the semaphores i created as described in the man page for sem_open and manipulate them.
I don't think it's the logic of the sem_post and sem_wait that's at fault here, since the program seems to ignore them.
So my question is. What goes wrong?
Edit: I don't really need the solution to the problem. Some guidance alone would be much appreciated and welcoming as an answer. Thank you in advance!
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void){
sem_t *semA = sem_open("/semA", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0); //Initialize semaphore(= 0) for process A
sem_t *semB = sem_open("/semB", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0); //Initialize semaphore(= 0) for process B
if (fork()){ // parent process
if(fork()){}
else{
sem_t *childsemA = sem_open("/semA", 0);
sem_t *childsemB = sem_open("/semB", 0);
while(1){
printf("A");
sem_post(childsemB);
sem_wait(childsemA);
}
}
}
else{
sem_t *childsemA = sem_open("/semA", 0);
sem_t *childsemB = sem_open("/semB", 0);
while(1){
printf("B"); // child2 process
sem_post(childsemA);
sem_wait(childsemB);
}
}
return 0;
}
Output:
May i suggest you to use System V semaphores? This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include "Semaphores.h"
#define SEM1_KEY (key_t)888
#define SEM2_KEY (key_t)1234
int sem1, sem2;
int main()
{
pid_t pid;
sem1 = semget(SEM1_KEY, 1, IPC_CREAT | 0666);
if(sem1 < 0)
{
fprintf(stderr, "\nSEMGET Failed\n");
exit(EXIT_FAILURE);
}
sem2 = semget(SEM2_KEY, 1, IPC_CREAT | 0666);
if(sem1 < 0)
{
fprintf(stderr, "\nSEMGET Failed\n");
exit(EXIT_FAILURE);
}
SEM_SET(sem1, 1);
SEM_SET(sem2, 0);
if((pid = fork()) == -1)
{
fprintf(stderr, "\nError in fork()\n");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
while(1)
{
SEM_WAIT(sem2);
printf("%c", 'B');
fflush(stdout);
sleep(1);
SEM_POST(sem1);
}
}
while(1)
{
SEM_WAIT(sem1);
printf("%c", 'A');
fflush(stdout);
sleep(1);
SEM_POST(sem2);
}
wait(0);
SEM_DEL(sem1);
SEM_DEL(sem2);
exit(EXIT_SUCCESS);
}
And this is the header file Semaphores.h which includes the System V semaphores implementation:
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds * buf;
unsigned short * array;
};
int SEM_SET(int sem_id, int sem_val)
{
union semun sem_union;
sem_union.val = sem_val;
return semctl(sem_id, 0, SETVAL, sem_union);
}
int SEM_DEL(int sem_id)
{
return semctl(sem_id, 0, IPC_RMID);
}
int SEM_WAIT(int sem_id)
{
struct sembuf sem_buf;
sem_buf.sem_num = 0;
sem_buf.sem_op = -1;
sem_buf.sem_flg = SEM_UNDO;
return semop(sem_id, &sem_buf, 1);
}
int SEM_POST(int sem_id)
{
struct sembuf sem_buf;
sem_buf.sem_num = 0;
sem_buf.sem_op = 1;
sem_buf.sem_flg = SEM_UNDO;
return semop(sem_id, &sem_buf, 1);
}
The result will be this:
ABABABABABABABABA and so on
fflush() was probably the problem, but your code has some leaks, you need to understand what is a critical section, and you need to check for the return values of fork().
in this program about shared memory(Producer/Consumer) with semaphores(on DEBIAN) when I use the strncmp function with the string "end", in order to turn on 0 a flag(running) to kill a while cycle,strncmp doesn't recognize the word end that I insert into the shell. Thank you.
This is only the first process that I want to use:
//CONSUMER
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "semafori.h" //semaphores SYSTEM V functions
#include <sys/shm.h>
#include <string.h>
#define SHM_KEY (key_t)1234
#define SEM_KEY (key_t)5678
#define WRITE_SEM 0
#define READ_SEM 1
#define TEXT_SIZE 2048
struct SharedData{
unsigned int count;
char text[TEXT_SIZE];
};
int main(void)
{
int running=1;
void *shmP;
struct SharedData * p;
int shmID;
int semID;
semID=semget(SEM_KEY,2,IPC_CREAT|0666);
SEM_SET(semID, WRITE_SEM,1);
SEM_SET(semID, READ_SEM, 0);
shmID=shmget(SHM_KEY, sizeof(struct SharedData), IPC_CREAT|0666);
shmP=shmat(semID, (void *)0, 0);
printf("Memoria agganciata all'indirizzo: %X\n", (int)shmP);
p=(struct SharedData *)shmP;
while(running!=0){
if(SEM_P(semID, READ_SEM)==-1) exit(EXIT_FAILURE);
if (strncmp(p->text, "end", 3) == 0) {
running = 0;
}
else {
printf("Numero scambi effettuato: %u\nHai scritto: %s\n", p->count, p->text);
}
if(SEM_V(semID, WRITE_SEM)==-1) exit(EXIT_FAILURE);
}
if(shmdt(shmP)==-1){
fprintf(stderr, "shmdetach failed\n");
exit(EXIT_FAILURE);
}
if(shmctl(shmID, IPC_RMID, 0)==-1){
fprintf(stderr, "shmctl RMID failed\n");
exit(EXIT_FAILURE);
}
SEM_DEL(semID, 0);
exit(EXIT_SUCCESS);
}
This is the second process:
PRODUCER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include "semafori.h"
#define SHM_KEY (key_t)1234
#define SEM_KEY (key_t)5678
#define WRITE_SEM 0
#define READ_SEM 1
#define TEXT_SIZE 2048
struct SharedData{
unsigned int count;
char text[TEXT_SIZE];
};
int main(void)
{
int running=1;
unsigned int count=0;
void *shmP;
struct SharedData *p;
int shmID, semID;
char buffer[TEXT_SIZE];
semID=semget(SEM_KEY, 2, IPC_CREAT|066);
shmID=shmget(SHM_KEY, sizeof(struct SharedData),IPC_CREAT|0666);
shmP=shmat(shmID, (void *)0, 0);
p=(struct SharedData*)shmP;
while(running!=0)
{
count++;
if(SEM_P(semID, WRITE_SEM)==-1) exit(EXIT_FAILURE);
printf("Inserisci testo: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(p->text, buffer, TEXT_SIZE);
p->count=count;
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
if(SEM_V(semID, READ_SEM)==-1) exit(EXIT_FAILURE);
}
if(shmdt(shmP)==-1){
fprintf(stderr, "shmdt failure\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
I resolved the problem with debug method. In the shmat argument i wrote semID instead of shmID shmP=shmat(semID, (void *)0, 0)
Thank you everybody.
[RESOLVED]
I am learning some simple producer/consumer examples involving semaphores, but having a hard time explaining to myself why I am getting a certain result (because I am a noobie to C).
When I run two concurrent processes of the following producer, both processes get hung up and never finish:
#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#define BUFF_SIZE 20
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
shared_data *shm, *s;
char sem_name1[] = "mutex";
char sem_name2[] = "empty_slots";
char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
void Put(char item)
{
sem_wait(empty_slots);
sem_wait(mutex);
s->buffer[s->nextIn] = item;
s->nextIn = (s->nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ... with pid = %d\n", item, getpid());
sem_post(full_slots);
}
void Producer()
{
int i;
for(i = 0; i < 10; i++)
{
sleep(rand()%3);
Put((char)('A'+ i % 26));
}
}
void main()
{
//Create and initialize the semaphores
mutex=sem_open(sem_name1, O_CREAT,0644, 1);
full_slots=sem_open(sem_name3, O_CREAT,0644, 0);
empty_slots=sem_open(sem_name2, O_CREAT,0644, 10);
//Create a key for the segment
key_t key;
key = 1234;
//create the segment
int shmid;
if ((shmid = shmget(key, sizeof(shared_data), IPC_CREAT |0666)) <0)
{
perror("Shmget");
exit(1);
}
//attach to the segment
if ((shm = (shared_data *) shmat(shmid, NULL, 0))==(shared_data *) -1)
{
perror("Shmat");
exit(1);
}
s=shm;
s->nextIn = 0;
Producer();
//detach from the segment
shmdt((void *) shm);
}
The output from the first and second processes, respectively:
Can someone help me understand why this happens (i.e. why do these processes never finish)? Have I created a deadlock? Why or why not? I am completely stumped.
Thanks!