Official website for Linux User & Developer
FOLLOW US ON:
Apr
6

Process synchronisation in Linux

by Swayam Prakasha

The two fundamental concepts in a Linux operating system are processes and time slice. A process is an instance of a program that is being executed by the computer’s operating system. When we say that two computers are communicating with each other, we mean that two processes, one running on each computer, are in communication with each other.

In some situations, we need to explicitly unlock a file. The same system call, lockf, will help us, but we need to pass F_ULOCK as a parameter. We mentioned that in the above example we passed a value of 0 as the third parameter to the lockf call. This resulted in the locking of an entire file. But in some cases, we may be interested in locking some part of a file. The third parameter passed to the lockf call is the number of bytes of the file that will be locked.

When we use files, we may encounter a situation known as ‘deadlock’. Take a look at the following program to understand this situation better:

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
main()
{
int fd,pid;
fd = open(“testfile”,O_RDWR);
lockf(fd,F_LOCK,10);
printf(“Parent locked 10 chars\n”);
pid = fork();
if (pid == 0)
{
lockf(fd,F_LOCK,10);
printf(“End of 1st Child process\n”);
}
else
{
wait(0);
printf(“End of Parent process\n”);
}
}

Here, we first open a file and lock the first ten bytes. Then a child process is forked and gets the time slice. In the child process, we try to lock ten bytes. But these have already been locked. Thus the child waits for the parent to unlock the file. But in the parent process, we have a wait() call and thus the parent waits till the child process is over. So we are in a situation where parent waits for the child and child waits for the parent. Hence a deadlock situation. Whenever such a situation occurs, Linux is smart enough to recognise it and sort it out. When Linux realises that a deadlock has occurred, it prints an error message and terminates the parent process.

Linux provides another synchronisation primitive – known as semaphores. Even though they are a form of IPC, they are not used for exchanging large amounts of data. They are basically intended to let multiple processes synchronise their operations. One main purpose of semaphore is to synchronise the access to a shared memory segment. As semaphores are used to provide resource synchronisation between various processes, it is natural to expect the value of a semaphore to be stored in the kernel.

To obtain a resource that is controlled by a semaphore, a process needs to test its current value. If the current value is greater than zero, then decrement the value by one. If the current value is zero, then the process needs to wait until the value is greater than zero. To release a resource that is controlled by a semaphore, a process increments the semaphore value. If some other process has been waiting for the semaphore value to become greater than zero, that other process can now obtain the semaphore.

Pages: 1 2 3 4 5 6 7 8
  • Tell a Friend
  • Follow our Twitter to find out about all the latest Linux news, reviews, previews, interviews, features and a whole more.

    2 Comments »

    • kdm said:

      A few points worth making, should anyone actually try to write programs using 1003.1 calls:

      1. It is technically incorrect to call non-async signal safe routines (ie. almost anything in the C library) after a fork(), but before exec().
      This is how deadlocks can be created, as your child process _could_ still be holding a mutex (for example, in the memory allocator). This can be particularly nasty in multi-threaded programs. I have fixed this bug in production code on several occasions.

      2. lockf()/fcntl()/file locking is useless. It doesn’t work on NFS volumes, and is unreliable anyway, so please don’t bother to suggest it. There _are_ schemes with lock files that can be atomic, however.

      To quote from the relevant man page:
      “The solution for performing atomic file locking using a lockfile is to create a unique file on the same filesystem (e.g., incorporating hostname and pid), use link(2) to make a link to the lockfile and use stat(2) on the unique file to check if its link count has increased to 2. Do not use the return value of the link(2) call.”

    • Rainer Weikusat said:


      1. It is technically incorrect to call non-async signal safe routines (ie. almost anything in the C library) after a fork(), but before exec().

      UNIX(*) is a superset of C and the set of UNIX(*) routines which are async-signal
      safe is much larger than the set of C library routines. Also, the statement above
      is theoretically only true for multithreaded processes and practically only
      relevant insofar locks are actually being held across fork.


      2. lockf()/fcntl()/file locking is useless. It doesn’t work on NFS volumes, and is unreliable anyway, so please don’t bother to suggest it.

      fcntl locks are not unreliable and they do work on NFS, minus halfway mythical
      problems with unknown rpc.lockd-implementations which reportedly existed on some
      nameless set of UNIX(*) platforms more than fifteen years ago. Personally, I doubt
      if these problems ever existed and weren’t just invented by people unwilling to
      let go of their habitual dot-locking hackery.

    What's your opinion?

    Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

    Be nice. Keep it clean. Stay on topic. No spam.

    * Required fields