Read-Write shared memory - c

I have a program in which i have a parent process and i want to create 3 children processes.
I also have created 2 shared memories (IN, OUT) and 1 semaphore for each shared memory.
The idea is:
The parent process has 3 integers and has to write in shared memory (IN) one of these integers. Then one of the children processes reads it, does some calculations and writes something in shared memory (OUT) from where the parent reads the result. Then the parent process adds the next integer to the shared memory and so on..
This is part of my code where i try to implement the first part (write-read from shared memory IN):
// create and attach shared memory
memidIN = shmget(...);
memidOUT= shmget(...);
pointerIN = (...) shmat(...);
pointerOUT = (...) shmat(...);
// create and init semaphores
semIN = semget(...);
semOUT = semget(...);
semctl(semIN, ...); // initialize both to 1
semctl(semOUT, ...);
for (i = 0; i < children; ++i)
{
pid = fork();
if (pid)
{
// parent process code
down sem_IN
write in shmIN
up sem_IN
}
else if (pid == 0)
{
// Children processes code
down sem_IN
read from shmIN
up sem_IN
exit(0);
}
else
//ERROR
}
// dont die until childrens die
for( j = 0; j < children; j++)
wait(&status);
The question is, how can i be sure that the children processes read the correct value? I mean if the parent process writes 5 then one process should take it, do something, write something in OUT. Then the parent should write another value, lets say 10.
In my program 5 could be read by the children processes 2 or more times.
Should i use a mutex semaphore to make sure that the children processes read the correct value and to make sure that the parent process updates the value when one of the children has read it?
Any ideas?

So, you can arrange data in you IN shared memory by this way:
int Number;
bool Number_IsRead; // Initialized by 'true'.
When you need to pass a Number, you should do
Number_IsRead = false;
Child should check Number_IsRead before reading Number.
When Number has read, child should assign true to Number_IsRead.
If you have 3 children who need to read Number, you should create 3 flags (bool Number_IsRead[3]).
Also you must use semaphores when you changing Number or Number_IsRead.
P.S. In general it is not a good idea to use shared memory instead of message queues (msgget/msgctl/msgsnd/msgrcv/etc.).

Related

How to read file using different processes?

I want to read a file using different processes but when i try that first created child read all file so other processes cannot read the file . For example i create 3 different process with 101,102 and 103 process ids.
a read from = 101.
b read from = 101.
c read from = 101.
d read from = 101.
But I wanted to read like that
a read from = 101.
b read from = 103.
c read from = 102.
d read from = 103.
I tried to solve it using semaphore and mutex but I couldn't do that. Could you help me, please?
int i=0, pid;
char buffer[100];
for(i=0; i<3; i++){
pid = fork();
if(pid == 0){
sem_wait(&mutex); // sem_t mutex is global.
while(read(fd,&buffer[j],1) == 1){
printf("%c read from = %d\n",buffer[j],getpid());
j++;
}
sem_post(&mutex);
exit(0);
}
else{
wait(NULL);
}
}
The problem is that even though each process has its own file descriptor, those file descriptors all share the same open file description ('descriptor' != 'description'), and the read position is stored in the file description, not the file descriptors. Consequently, when any of the children reads the file, it moves the file pointer for all the children.
For more information about this, see the POSIX specifications for:
open()
dup2()
fork()
No mutex or other similar gadget is going to fix this problem for you — at least, not on its own. The easiest fix is to reopen the file in the child processes so that each child has a separate open file description as well as its own file descriptor. Alternatively, each child will have to use a mutex, rewind the file, read the data, and release the mutex when done. It's simpler to (re)open the file in the child processes.
Note that the mutex must be shared between processes for it to be relevant. See the POSIX specification for pthread_mutexattr_setpshared(). That is not set with the default mutex attribute values.
You have two problems that prevent what you appear to want and will result in the entire file being read by (just) the first child
the parent process waits for each child immediately after creating it, before forking any more children. So after creating the first child, it will wait for that child to exit looping and creaing a second child. To fix that, you need have two loops parent -- the first just creates children and the second waits for them:
for (...) {
if (fork() == 0) {
// run the child
exit(0); } }
for (...)
wait(NULL); // wait for a child
your reading loop is inside the sem_wait/sem_post. So the first child will get the mutex, then proceed to read the entire file before releasing the mutex. Subsequent children will not get the mutex until the file is fully read, so they'll see they're at the EOF and exit. To fix this you need to move the sem_wait/sem_post calls inside the while loop:
while (!done) {
sem_wait(&mutex);
if (read(...) == 1) { ...
} else {
done = true; }
sem_post(&mutex); }
You might not even need the semaphore at all -- the kernel will synchronize reads between the different processes, so each byte will be read by exactly one child. This would allow the children to proceed in parallel (processing the bytes) rather than only allowing one child at a time to run.
Of course, even with the above, one child may process many bytes before another child starts to run and process them, so if the processing is fast and there are few bytes, they might still all be consumed by the first child.

Understanding fork() order in C

So I have this program I'm trying to understand, its from an old exam but I just cant get a grip of it. How do I know the order of the forks and how the variables are changed?
static int g = -1;
int main(int argc, char *argv[])
{
int v = 0;
pid_t p;
while (v++ < 6)
if ((p = fork()) < 0) {
perror("fork error");
return 1;
} else if (p == 0) {
v++;
g--;
} else {
g++;
v+=3;
if (waitpid(p, NULL, 0) != p) {
perror("waitpid error");
return 1;
}
}
printf("mypid = %d parentpid = %d p = %d v = %d g = %d\n",
getpid(), getppid(), p, v, g);
return 0;
}
Each call to fork generates its own process with its own variables, which are copied at the time of the call (logically; optimization may change when the actual copy happens, but not in a way that'll change the outcome).
So when you enter the loop, v gets incremented to 1, then you fork. At this point the parent process has g=-1, v=1, p= and the new child has g=-1, v=1, p=0. The parent then drops into the else case, incrementing g to 0 and v to 4 and then waiting for the child to complete, whereas the child drops into the "else if (p == 0)", increments v to 2, decrements g to -2, and goes around the loop again.
From there, you've hopefully now got enough information to follow the logic as the next two child processes get forked off, finish off the loop, and print their respective results. When they do, the first child will also come to the end of its waitpid with v=6, drop out of the loop, and print its results.
At this point, the parent will unblock, go around the loop one more time (forking off one more child along the way), and (once that child has completed) drop out of the loop.
The call to fork() both starts a new process and continues the old one. If there is some kind of error, it returns an error value. All errors and only errors are negative numbers. This is what the first if block checks.
In the new process, fork() returns 0. The branch that increments v and decrements g is therefore called only in the child process, not the parent.
In the original process, the fork() function returns the process identifier (PID) of the daughter process, which is a positive integer. (This will later be passed to waitpid(). Therefore, the branch that decrements v and increments g is only called in the parent process, not the child.
Each process has its own copy of v and g. (That’s the main difference between a process and a thread: threads share memory.) On a modern SMP operating system, what will happen is that the child process gets a copy of the parent’s memory map. but these refer to the same pages of physical memory until one process or the other writes to them. When that happens, a copy is made of that page of memory and both processes now get their own, different copies.
The way modern Linux kernels implement fork(), the child process will continue before the parent does. This made a significant difference to performance. Most programs that call fork() immediately have the child process call exec() to start a new program. That means it isn’t going to need its copy of the parent’s memory at all. (There is a newer, simpler way to start a different program in a new process now, posix_spawn().) The parent process, on the other hand, almost always keeps running and modifying its memory. Therefore, giving the child the chance to declare that it’s going to discard the memory it inherited means that the parent doesn’t need to worry about leaving an unmodified copy of any memory pages for its children, and the kernel does not have to go through the rigmarole of copy-on-write.
In practice, though, any decent compiler will keep both local variables in registers, so this issue will not arise.
On the next iteration of the loop, which only happens after the child process terminates, a new child process is spawned using the updated values of the parent’s variables. Each child process also continues to run the loop with the same values of v and g that it inherited from its parent.

Synchronising processes with semaphores

I'm having a tricky time understanding how to alternate control between two processes using semaphores. Here's a contrived example of the process handling code.
int pid = fork();
if (pid) {
int counter = 0;
while (true) {
counter += 1;
printf("P%d = %d", pid, counter);
}
} else {
int counter = 0;
while (true) {
counter += 1;
printf("P%d = %d", pid, counter);
}
}
I was expecting the above code to run in parallel, but it seems like control flow continues instantly for the forked process and only later resumes for the parent process.
This is fundamentally breaking my existing code that uses a semaphore to control which process can act.
int id = get_semaphore(1);
int pid = fork();
if (pid) {
int counter = 0;
while (true) {
sem_wait(id);
counter += 1;
printf("P%d = %d\n", pid, counter);
sem_signal(id);
}
} else {
int counter = 0;
while (true) {
sem_wait(id);
counter += 1;
printf("P%d = %d\n", pid, counter);
sem_signal(id);
}
}
The sem_wait helper just subtracts 1 from the semaphore value and blocks until the result is > 0 (uses semop under the hood).
The sem_signal helper just adds 1 to the semaphore value (uses semop under the hood).
I'd like the code to alternate between the two processes, using sem_wait to block until the other process releases the resources with sem_signal. The desired output would be:
P1 = 0
P0 = 0
P1 = 1
P0 = 1
...
However, because of the initial execution delay between the processes, the child process takes the available semaphore resource, uses it to print a number, then restores it and loops — at which point the resource is available again, so it continues without ever waiting for the other process.
What's the best way to prevent a process from using resources if it released them itself?
it seems like control flow continues instantly for the forked process and only later resumes for the parent process
That is because stream IO buffers the output on stdout until either
the buffer is full
fflush() is called on stdout
a newline (\n) is encountered
In your program, each process will fill a buffer before sending its contents to stdout giving the appearance of one process running for a long time, then the other. Terminate the format strings of your printf statements with \n and you'll see behaviour in your first program more like you expect.
I am not sure why your semaphore thing isn't working - I'm not very knowledgeable about system V semaphores but it seems like a red flag to me that you are getting the semaphore after you have forked. With the more common POSIX semaphores, the semaphore has to be in memory that both processes can see otherwise it's two semaphores.
Anyway, assuming your get_semaphore() function does the right thing to share the semaphore, there is still a problem because there is no guarantee that, when one process signals the semaphore, the other one will start soon enough for it to grab it again before the first process loops round and grabs it itself.
You need two semaphores, one for the parent and one for the child. Before the print each process should wait on its own semaphore. After the print, each process should signal the other semaphore. Also, one semaphore should be initialised with a count of 1 and the other should be initialised with a count of 0.
Semaphores have two general use cases. One is mutual exclusion and the second is synchronization. What's been done in your code is mutual exclusion. What you actually want is synchronization (alternation) between the parent and child processes.
Let me explain a bit:
Mutual exclusion means that at any time only once process can access a "critical section" which is a piece of code that you want only one process/thread to access at a time.Critical sections generally have a code that manipulates a shared resource.
Coming to your code, since you have used only a single semaphore, there is no guarantee as to the "order" in which each process is allowed to enter the critical section.
ex: sem_wait(id) from your code can be executed by any process and it's not necessary that the two processes should alternate.
For process synchronization (more specifically alternation), you need to use two semaphore one for parent and another for child.
Sample code:
int pid = fork();
int parent_sem = get_semaphore(0);
int child_sem = get_semaphore(1);
if (pid) {
int counter = 0;
while (true) {
sem_wait(child_sem);
counter += 1;
printf("P%d = %d", pid, counter);
sem_signal(parent_sem);
}
} else {
int counter = 0;
while (true) {
sem_wait(parent_sem);
counter += 1;
printf("P%d = %d", pid, counter);
sem_signal(child_sem);
}
}
You need to initialize one semaphore (in my case child) to 1 and the second one to zero. That way only of the two processes get to start while the other enters into wait. Once child is done printing, it signals the parent. Now child's semaphore value is zero so it waits on wait(child_sem) while the parent that was signaled by the child executes. Next time, parent signals child and it executes. This continues in alternating sequences and is a classic synchronization problem.

A struct for each child process and accessing the members

So I'm forking a couple of child processes and each of them is supposed to take a line that I've read from a file and do operations on them.
What I have is a struct containing the lines like :
struct query {
char lines[LINESIZE];
};
and I have an array of structs. So each struct serves to one child process.
This is how I forked my child processes :
for(i=0; i<5; i++) {
n = fork();
}
And say I have five structs to serve for each of these processes.
struct query query[5];
So First processes takes query[0].lines and do some operations on it, second process gets query[1].lines and does the same operations on it and so on ...
Should I use pipe to pass values between processes? I feel like there's a much simpler solution to this but my lack of practice and knowledge in C is really slowing me down.
I suppose you're trying to spawn 5 processes, but in the code that you posted you'll end up creating way more than 5 processes, in fact in:
for(i = 0; i < 5; ++i) {
n = fork();
}
when i = 0 you'll fork a process, since the forked process is an exact copy of the parent it will continue in the for loop, so at that point you'll have two processes each one having i = 1 and forking each one a new process, then you'll have at this point 4 processes, when the loop is complete you have created 160 processes.
Allocating and initializing the array "query" before the forking it is perfectly fine what you have to fix is the spawning. The fork() call returns 0 in the child process, the process id of the child to the parent process or -1 if there was a error. Knowing if the current process is the parent or the child we can continue or break out of the loop and do the computation:
for(i = 0; i < 5; ++i) {
if(fork() == 0) {
/* child process */
process_query(query[i]);
exit();
}
}

Parent is executing before child process, how to force opposite through semaphores?

I am having trouble using shared memory, semaphores and forks in Unix C. My semaphores are not posix.
I create a pointer to shared memory 2*sizeof(float).
I initialize the value of my semaphore to 2 with semctl.
I do a fork() in a for loop (i<2).
In the child processes (if fork() == 0) each child does a p operation on the semaphore (-1), writes to shared memory then does a v operation (+1) then exits. The Parent process does a p operation (-2) on the semaphore, reads the entirety of the shared memory segment(with a for loop) and does a v operation (+2). He waits on the child processes before exiting to avoid zombies.
The problem i have in output is that i get :
Parent reading 0
Parent reading 1
Parent reading 0
Parent reading 1
Child writing 0
Child writing 1
When what i should be getting is :
Child writing 0
Child writing 1
Parent reading 0
Parent reading 1
I have tried initializing my semaphore to 1 instead of 2 but that just stalls the program since the semaphore will never have a value of two and thus the parent process will never read.
If what i have understood about semaphores is correct, the fact that i initialize it to 2 means that the parent process can directly read even though none of the children have written anything. How can i resolve this problem?
EDIT: I added a simplified version of my code after request, i have removed error checking, and waiting for children to reduce length.
/** OPEN MEMORY **/
int shmid1 = shmget(1990, (size), IPC_CREAT | 0666 );
float * shmPt = (float*)shmat(shmid1, NULL, 0);
/** CREATE INITIALIZE SEMAPHORE **/
semun1.val = 2;
int semid = semget(1991, 1, 0666 | IPC_CREAT)
semctl(semid, 0, SETVAL, semun1 )
/** CREATE PROCESSES **/
for ( ii = 0; ii < 2; ++ii) {
if ((p = fork()) == 0) {
int semid = semget(1991, 1, 0666);
struct sembuf p_buf;
p_buf.sem_num = 0;p_buf.sem_op = -1;p_buf.sem_flg = SEM_UNDO;
/** LOCK **/
semop(semid, &p_buf,1);
/** WRITE **/
shmPt[ii] = RandomFloat;
v_buf.sem_num = 0;v_buf.sem_op = 1;v_buf.sem_flg = SEM_UNDO;
/** UNLOCK **/
semop(semid, &v_buf,1)
exit(0);
}
else {
int semid = semget(1991, 1, 0666);
struct sembuf p_buf;
p_buf.sem_num = 0;p_buf.sem_op = -2;p_buf.sem_flg = SEM_UNDO;
/** LOCK **/
semop(semid, &p_buf,1);
/** READ **/
for(int j =0;j<2;j++) tabFloat[j] = shmPt[j];
v_buf.sem_num = 0;v_buf.sem_op = 2;v_buf.sem_flg = SEM_UNDO;
/** UNLOCK **/
semop(semid, &v_buf,1)
}
}
EDIT :
My ultimate goal is to have 24 children writing one by one into a shared memory segment of the same size and only when it is full, then the parent can read everything and process the information. On top of that all of this needs to be in a while loop (imagine 24 cars that keep generating random times everytime they complete a lap until the first car has finished 50 laps)
You're mis-using semaphores. The general idea is that a semaphore counts "how many entities (threads, whatever) are allowed to use this data right now". By starting the count at 2, you're saying "two threads may use this now". Semaphores do not say which entities, nor how (read vs write), only how many. For example, semaphores can to be used to count the number of retrievable items in a producer/consumer queue: the producer increments and the consumer decrements. (Of course, semaphores come in all kinds of expanded flavors; since you say these are "not POSIX", but not what they are, it's hard to generalize much more.)
One way to make this work as described—but of course, actual code tends to vary from descriptions—is to start the semaphore count at 0, fork a child, have the child write without looking at the semaphore count, fork another child, have that child also write without looking at the semaphore count, and then have the parent wait on the semaphore (P). That is, the semaphore says "none shall pass" but the children don't actually look at it. Then, the two children each do V operations (+1 in each). Once the semaphore has gone to 1, the parent starts: he can then find at least one (but perhaps only one) child-result. The parent can do another P immediately if he needs to have both results.
(More generally, though, you may want reader/writer locks or mutexes and condition variables. If you have POSIX threads, see pthread_cond_init(), pthread_cond_wait(), pthread_cond_signal(), pthread_mutex_init(), etc.)
Aha, from the comment and question-edit, I see that you're using the wretched System V shared memory and semaphore interface.
Are you really stuck with that? The POSIX thread stuff is nicer, in my opinion (and generally lighter-weight).
How do you intend to organize your shared-memory? You may get less lock-contention if each car has its own lap times region, shared only with the display thread/proc: there's one single producer (the car) and one single consumer (display thread/proc), but 24 such locks (one per car). If all cars share one shared-memory region with the display thread/proc, you need only one lock, but it's much more active. Which one is "better" depends on what you are doing.
And, if you want to wait for "some car to finish 50 laps", consider having each car have its own private (or possibly shared-with-display) counter, and one counting semaphore for "number of cars that have hit 50 laps". Each car simply counts up and upon reaching 50, increments the counting semaphore (once) too.
Final (I hope) edit: after fixing smaller problems, the last remaining one was the use of SEM_UNDO in each child process, which would do a V (of +1) to signal "data produced and all done" and then exit. SEM_UNDO records a balancing adjustment value that is applied on process exit, so the semaphore would count up, but then immediately count right back down, leaving the parent waiting for another V that would never occur.

Resources