Sunday, January 10, 2010

Semaphore and Mutex RE-Discussion

A mutex is actually a semaphore with value 1
This is Totally wrong

Semaphore : Its simple counters that indicate the status of a resource . Counter is managed by Kernel and can be accessed by API
Any thread can decrement the count to lock the semaphore (this is also called waiting on the semaphore)
Unlike mutexes, it is possible for a thread that never waited for (locked) the semaphore to post (unlock) the semaphore. This could cause unpredictable application behavior. We should avoid this if possible.
// Wait Getting resource 
W(s) 
while  (s<=0)    {
//do  nothing 
}
s=s-1;

API :sem_wait(&sem_name);   // proto  
Funtioning : If the value of the semaphore is negative, the calling process blocks; one of the blocked processes wakes up when another process calls sem_post.

//Signal Releasing Resource 
P(s)
s=s+1;

API sem_post(&sem_name)
Functioning: It increments the value of the semaphore and wakes up a blocked process waiting on the semaphore, if any

API to create  Unnamed Semaphore 
int sem_init(sem_t *sem, int pshared, unsigned int value)
API for Named 
sem_t *sem_open(const char *name, int oflag, ...);
Counting Semaphore :used where Resources are more as memory pool , socket pool.  
Binary semaphore : count = 1  

POSIX semaphore - two type :  

a.    NAMED semaphore : A named semaphore is identified by a name of the form /somename. Two processes can operate on the same named semaphore by passing the same name to sem_open. This implies that these semaphores, like System V, are system-wide and limited to the number that can be active at any one time.
The advantage of named semaphores is that they provide synchronization between unrelated process and related process as well as between threads.
The sem_open(3) function creates a new named semaphore(if it doesn,t Exists) or opens an existing named semaphore. After the semaphore has been opened, it can be operated on using 
sem_post() and sem_wait().
  When a process has finished using the semaphore, it can use
sem_close() to close the semaphore. When all processes have finished using the semaphore, it can be removed from the System using sem_unlink().

b.   UNNAMED Semaphore /Memory Semaphore :
An unnamed semaphore does not have a name. Instead the semaphore is placed in a region of memory that is shared between multiple threads (a thread-shared semaphore) or processes (a process-shared semaphore). A thread-shared semaphore is placed in an area of memory shared between by the threads of a process, for example, a global variable.
A process-shared semaphore must be placed in a shared memory region (e.g., a System V shared memory segment created using semget(2), or a POSIX shared memory object built created using shm_open(3)).
It is used between Related process like forked one. They are not available system wide. sem_open call is not required .
sem_t semid;
int sem_init(sem_t *sem, int pshared, unsigned value);
Working :  if pshared has the value 0, then the semaphore is shared between the threads of a process, and should be located at some address that is visible to all threads (e.g., a global variable, or a variable allocated dynamically on the heap).    If pshared is non-zero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent's memory mappings, it can also access the semaphore.) Any process that can access the shared memory region can operate on the semaphore using sem_post(3), sem_wait(3), etc. Initialising a semaphore that has already been initialised results in undefined behaviour Before being used, an unnamed semaphore must be initialised using sem_init(3).
It can then be operated on using sem_post(3) and sem_wait(3).
When the semaphore is no longer required, and before the memory in which it is located is deallocated, the semaphore should be destroyed using sem_destroy(3).  
-----------------------------------------------------------------------------------------------------------------------------
Mutex: The mutex is similar to the principles of the binary semaphore with one significant difference: the principle of ownership. When a task(Thread) locks (acquires) a mutex ONLY it can unlock (release) it. If a task tries to unlock a mutex it hasn’t locked (thus doesn’t own) then an error condition is encountered and, most importantly, the mutex is not unlocked.  
Anytime a global resource is accessed by more than one thread the resource should have a Mutex associated with it. One can apply a mutex to protect a segment of memory ("critical region") from other threads.
Mutexes can be applied only to threads in a single process and do not work between processes as do semaphores.

Pros : Problem of Accidental Release Can't happen
Uses : Mutexes are used to prevent data inconsistencies due to race conditions. A race condition often occurs when two or more threads need to perform operations on the same memory area, but the results of computations depends on the order in which these operations are performed. Mutexes are used for serializing shared resources.


How to avoid Death Detection of thread who has locked Mutex??
pthread_mutex_trylock()--will attempt to lock a mutex. However, if the mutex is already locked, the routine will return immediately with a "busy" error code

PS: All above Information is for POSIX - semctl() and semop() system calls are in SYSTEM V which is bit clumsy to use . and heavy also .
ipc -s will not show posix semaphore This command is for System V

Refer this link
http://www.feabhas.com/blog/2009/09/mutex-vs-semaphores-part-1-semaphores.html http://linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html http://linux.die.net/man/7/sem_overview Process memory -
http://virtualthreads.blogspot.com/2006/02/understanding-memory-usage-on-linux.html  

OPEN Question what is sem_trywait pthread_mutex_trylock()
----------------------------------------------------------------
Consumer Producer Problem two thread one writes in buffer and one reads (removes ) form the same , Idea is writer should not write if its full , It should wait til some data is freed Reader should not read if tis Empty but wait till it gets fill
Algorithm   :
semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE
procedure producer() {
     while (true) {
         item = produceItem()
         down(emptyCount)  
         putItemIntoBuffer(item)
         up(fillCount)
       }
}
procedure consumer() {
     while (true) {
        down(fillCount) item = removeItemFromBuffer()
        up(emptyCount)
        consumeItem(item)
       }
}
Code :
Links
http://en.wikipedia.org/wiki/Producer-consumer_problem
http://linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html?page=6

No comments: