thank you for taking your time to read this. I'm trying to implement a semaphore through a file using C on a linux machine.
I have two process that I must synchronize, one has all the consonants of a file stored in an array, the other has all the vowels. I've arranged these arrays so that if I alternate between them, I can reconstruct the original file and paste it in another file. The issue now is making these two process alternate. This exercise in particular wants me to implement a semaphore using a 3rd file. What I've done is use the first byte of this file as a semaphore, lot loop one process until the other is finished.
I've tested with long sleep()s and yes, if these processes do alternate, the output file is exactly how I want it, but with that said, my current implementation of a semaphore seems not to be working.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
int main (){
int child1=0, child2=0, fd, fd2, fs, i=0, i2=0;
int count=0, count2=0;
char buf1[20], buf2[20], a, b, con='1', vow='0', check1, check2;
fd=open("text", O_RDONLY);
fd2=open("text2", O_CREAT|O_RDWR|O_TRUNC,0777);
fs=open("semaphore", O_RDWR, 0777);
if (fork()==0)
child1=1;
else {
if (fork()==0)
child2=1;
}
//access vowel child
if (child1){
printf("I'm the first child\n");
while ((read(fd,&a,1))==1){
if (a=='a' || a=='e' || a=='i' || a=='o' || a=='u')
buf1[count]=a;
count++;
}
printf("count: %d\n", count);
//vowels are now into buf1
//wait for the brother to do the same
sleep(2);
for (i; i<=count+1; i++){
if (buf1[i]!='\0'){
printf("%c\n", buf1[i]);
a=buf1[i];
write(fd2,&a,1);
}
lseek(fs,0,SEEK_SET);
write(fs,&con,1);//tell the semaphore it's the consonant's turn (1)
while(check1=='1'){
lseek(fs,0,SEEK_SET);
read(fs,&a,1);
check1=a;
sleep(1);
} //get stuck until it's somebody's else turn
}
}
//access consonant child
else if (child2){
sleep(1);
lseek(fd,0,SEEK_SET);
printf ("I'm the second child\n");
while ((read(fd,&a,1))==1){
if (a=='a' || a=='e' || a=='i' || a=='o' || a=='u')
;
else
buf2[count2]=a;
count2++;
}
//resync
sleep(1);
printf("count: %d\n", count2);
//consonants are now into buf1
for (i; i<=count2+1; i++){
lseek(fs,0,SEEK_SET);
if (buf2[i]!='\0'){
printf("%c\n", buf2[i]);
b=buf2[i];
write(fd2,&b,1);
} //wait for vowel
while(check2=='0'){
lseek(fs,0,SEEK_SET);
read(fs,&b,1);
check2=b;
sleep(1);
}
lseek(fs,0,SEEK_SET);
write(fs,&vow,1);//tell the semaphore it's the vowel's turn (0)
}
}
else
printf("I'm the father\n");
sleep(10);
exit(0);
}
The file "text" has "hello world" stored in it. What happens when I execute this code is that what's copy and pasted is "hll wrld eoo". What exactly am I doing wrong with my semaphore?
Basically, you want to implement acquire/release similar to
pthread_mutex_torsem_t.You need two functions:
acquireto wait for and acquire ownershipreleaseto release ownership and grant it to the "other" processYou're conflating the two operations into one. And, your code doesn't actually do locking properly.
Side note: You are creating "zombie" processes because the father does not do
waiton the children.Here's some refactored code.
I added
acquireandreleasecalls to the places where you had your sempahore code (e.g. the second loops for each child). But, you might need them in the first loops as well (which I did not do).UPDATE:
The two child processes share a common file position for the semaphore file because the
opencall is done in the parent.So, there is a potential race condition between the
lseekand thereadorwrite.There are two ways to solve this:
fork. Then, they do not share the file position.lseekfollowed byreadorwrite, usepreadorpwrite.Here is the latter: