Tag Archives: posix

Using Semaphore in C coding (Posix)

Semaphore is used for dealing with the synchronisation problem between processes and threads. It is well defined library structure that comes with the POSIX libraries.

Here a example that have a thread synchronisation problem between two threads. Here is the code.


#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define UPTO 10000000
int count = 0;
void * ThreadAdd(void * a)
{
int i, tmp;
for(i = 0; i < UPTO; i++)
{
sem_wait(&mutex);
tmp = count;      /* copy the global count locally */
tmp = tmp+1;      /* increment the local copy */
count = tmp;      /* store the local value into the global count */
//printf("The count is %d in %dn", count, (int)pthread_self());
sem_post(&mutex);
}
}
int main(int argc, char * argv[])
{
pthread_t tid1, tid2;
if(pthread_create(&tid1, NULL, ThreadAdd, NULL))
{
printf("n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&tid2, NULL, ThreadAdd, NULL))
{
printf("n ERROR creating thread 2");
exit(1);
}
if(pthread_join(tid1, NULL))    /* wait for the thread 1 to finish */
{
printf("n ERROR joining thread");
exit(1);
}
if(pthread_join(tid2, NULL))        /* wait for the thread 2 to finish */
{
printf("n ERROR joining thread");
exit(1);
}
if (count < 2 * UPTO)
printf("n BOOM! count is [%d], should be %dn", count, 2*UPTO);
else
printf("n OK! count is [%d]n", count);
pthread_exit(NULL);
}

This code will have the synchronisation problem when you use it since the shared variable count will be updated with two threads unexpectedly. Consider the "for" section of the function "ThreadAdd". In that section count variable is updated but this increment and update action is not atomic operation (that means, it needs multiple system calls in low level) so in the middle of the for loop the other thread can get the control and continue its execution. As a result it causes unexpected result. Let's analysis execution flow of the threads.

initially "count = 1"

Thread 1:
tmp = count;
tmp = tmp+1
Thread2
Thread2
Thread2
count = tmp //(count = 2)

Thread 2:
Thread1
Thread1
tmp = count;
tmp = tmp+1
count = tmp  //(count = 2)  Two for loops the give same result for count. So result is 2 instead of 3

For this kind of problems we can easily use Semaphore. Here the basic functions:

sem_t sem_name; //create variable

sem_init(&sem_name, Flag, Init_val) // initialise the semaphore var. "Flag" decides whether it is shared by processes. "Init_val" is the initial value of the semaphore.

sem_wait(&sem_name);//waits while semaphore value will  be positive, if value is positive it makes the semaphore negative again to make he other processes waiting.

sem_post(&sem_name);//increment the semaphore value, so one of the waiting thread can continue its operations.

sem_destroy(&sem_name);

Here the solution of the above code with semaphore:

;
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#define UPTO 10000000
int count = 0;
sem_t mutex;
void * ThreadAdd(void * a)
{
int i, tmp;
for(i = 0; i < UPTO; i++)
{
sem_wait(&mutex);
tmp = count;      /* copy the global count locally */
tmp = tmp+1;      /* increment the local copy */
count = tmp;      /* store the local value into the global count */
//printf("The count is %d in %dn", count, (int)pthread_self());
sem_post(&mutex);
}
}
int main(int argc, char * argv[])
{
pthread_t tid1, tid2;
sem_init(&mutex, 0, 1);
if(pthread_create(&tid1, NULL, ThreadAdd, NULL))
{
printf("n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&tid2, NULL, ThreadAdd, NULL))
{
printf("n ERROR creating thread 2");
exit(1);
}
if(pthread_join(tid1, NULL))    /* wait for the thread 1 to finish */
{
printf("n ERROR joining thread");
exit(1);
}
if(pthread_join(tid2, NULL))        /* wait for the thread 2 to finish */
{
printf("n ERROR joining thread");
exit(1);
}
if (count < 2 * UPTO)
printf("n BOOM! count is [%d], should be %dn", count, 2*UPTO);
else
printf("n OK! count is [%d]n", count);
sem_destroy(&mutex);
pthread_exit(NULL);
}

Share

Using Pipes for IPC in C

I am developing a program that utilises the pipe system of POSIX for my Operating system course. I want to share my experience with you. There might be some flaws in my explanations and in that case please WARN ME?

Then, lets start some explanation for beginning. Pipes system is used for (Inter-process Communication) IPC between related processes. Related means that the processes having parent-child relation or sibling relation. It is not possible to use pipes for unrelated process communication. In addition the another limitation of the pipes is that one pipe just gives uni-directional communication between processes so if you want to have both direction communication, you might use two distinct pipes that have different directions in the way of sharing data (one pipe to send data form parent to child, one pipe to send data from child to parent). Another restriction of the pipe system, it is not the best way to share big data between processes (Using shared memory structure may be suitable) but it is the most common way.

Now here the basic process of coding in C:

First #include stdio.h(standard input output library) stdlib.h (standard library) unistd.h(POSIX depended functions library)

Create the pipe with "pipe(fd)". fd is the array to keep the file descriptors that are returned by the function. These descriptors points the "files" that are created after the function to provide read and write. (By the way, pipes are respected as files in the system. Thus each read and write action manipulated like file objects). Here is the code:

int fd[2];
pipe(fd);

After you create the pipe, if you "fork()" the process, it creates a child process that inherits all the information about the pipe so it is okay to communicate with the pipes.

I give an example code taken and little manipulated by myself form a pdf. In this implementation, by using the file descriptors we create file objects. In that way, this is possible to use standard C functions to read and write pipes. (Also you can get the PDF file from here).

Here
the link for below code:

#include
#include
#include
#include

/* Read characters from the pipe and echo them to stdout. */

void
read_from_pipe (int file)
{
FILE *stream;
int c;
stream = fdopen (file, "r");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
}

/* Write some random text to the pipe. */

void
write_to_pipe (int file)
{
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, "hello, world!n");
fprintf (stream, "goodbye, world!n");
fclose (stream);
}

int
main (void)
{
pid_t pid;
int mypipe[2];

/* Create the pipe. */
if (pipe (mypipe))
{
fprintf (stderr, "Pipe failed.n");
return EXIT_FAILURE;
}

/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0)
{
/* This is the child process.
Close other end first. */
close (mypipe[1]);
read_from_pipe (mypipe[0]);
return EXIT_SUCCESS;
}
else if (pid < (pid_t) 0) {
/* The fork failed. */
fprintf (stderr, "Fork failed.n");
return EXIT_FAILURE; }
else { /* This is the parent process. Close other end first. */
close (mypipe[0]);
write_to_pipe (mypipe[1]);
return EXIT_SUCCESS;
}
}

Also there is another way of using pipes by using "popen" as named pipe implementation. It is more generalised way of doing and avoids all the file object creation. You can get more info from the pdf.

Share

IPC (Interprocess Communication) implementation example.

This example code illustrates the basic implementation of IPC mechanism that is provided by POSIX API.


#include
#include shm.h>
>#include stat.h>
>
int main(int argc, char **argv)
{
int segment_id;
char *shared_mem;
const int size = 5096; // in bytes

//create shared mem.
segment_id = shmget(IPC_PRIVATE, size, S_IRUSR|S_IWUSR);

//attach the shared mem. to the process in Write Read mode.(0 argument)
shared_mem = (char * )shmat(segment_id, NULL, 0);

//write the data to the shared memory.
sprintf(shared_mem, "This is the shared memory example coded by Eren Golge. Regards!!");

//read the data from
printf("*%s n", shared_mem );

//detach the segment from process
shmdt(shared_mem);

//delete the shared mem. segment form memory
shmctl(segment_id, IPC_RMID, NULL);

printf("End of code");
return 0;
}

Share