POSIX semaphore __linux of Linux process synchronization

Source: Internet
Author: User
Tags mutex posix readable semaphore semaphore code terminates


POSIX semaphores are real-time extensions that are part of the POSIX standard system interface definition. The XSI IPC defined in the SUS (Single UNIX specification) specification also defines the system interface that people commonly refer to as Systems v semaphores. As a tool for interprocess synchronization, semaphores are a common type of synchronous IPC.



In "UNIX Network programming Volume 2: interprocess communication," the second and 1th edition of the difference between the author mentioned "POSIX IPC functions of the general trend, because they have more advantages than the corresponding parts of System V ", here the advantages I have to slowly understand ah ... <T_T>



Semaphores are a tool for synchronizing between processes, and of course security for threads is certainly safe, so semaphores can naturally be used for synchronization of different threads within the same process.



The reason that there are mutexes and conditional variables also provides semaphores is that the primary purpose of semaphores is to provide a way of synchronizing between processes. Processes of this synchronization can be shared or do not share memory areas. While the intent of semaphores is to synchronize between processes, the intent of mutexes and condition variables is to synchronize between threads, but semaphores can also be used for synchronization between threads, and mutex and condition variables can also be synchronized between processes through shared memory areas. However, specific options should be taken into account in terms of efficiency and ease of use. 1 POSIX semaphore operations



There are two types of POSIX semaphores: known semaphores and nameless semaphores, and nameless semaphores are called memory based semaphores. Known semaphores are synchronized between processes through the IPC name, and nameless semaphores, if not placed in shared memory areas between processes, cannot be used for interprocess synchronization and can only be used for thread synchronization.



There are three kinds of POSIX semaphore operations:



(1) Create a semaphore . The created procedure also requires the initialization of the semaphore's value.



Depending on the value of the semaphore (representing the number of available resources), POSIX semaphore can also be divided into: two-value signal : The value of the signal is only 0 and 1, which is very type of mutex, if the resource is locked, the signal value of 0, if the resources available, the signal value of 1; count semaphore : Semaphores have a value of 0 to a limit greater than 1 (POSIX indicates that the maximum limit for the system must be 32767). The count represents the number of available resources.



(2) waiting for a semaphore (wait). This action checks the semaphore's value, if its value is less than or equal to 0, blocking until the value becomes greater than 0, and then waits for the process to reduce the semaphore value by 1, and the process gains access to the shared resource. This entire operation must be an atomic operation. The operation is also often referred to as the P operation (Dutch proberen, meaning: try).



(3) Hang out a semaphore (post). This action adds a semaphore value of 1, and if a process blocks waiting for the semaphore, one of the processes is awakened. The operation must also be an atomic operation. This operation is also often referred to as V operation (Dutch Verhogen, meaning: Increase)



The following illustrates the classic producer-consumer problem, where individual producers and consumers share a buffer;



Here is the pseudo code that the producer and the consumer synchronize:





Initialization of the semaphore get
= 0;//represents the number of readable resources
put = 1;//represents the number of writable resources

//producer process                               //consumer process for
(;;) {for                                    (;;) {
Sem_wait (put);                                 Sem_wait (get);
Write shared buffer;                               read shared buffer;
sem_post (get)                                 ; Sem_post (Put);
}                                           
The above code is generally as follows: when producers and consumers start running, the producer gets the put semaphore, at which point put 1 indicates that resources are available and the producer enters the shared buffer for modification. And the consumer gets the get semaphore, and at this point getting is 0, which means there is no resource to read, so the consumer enters the wait sequence until the producer produces a data, and then the producer notifies the waiting consumer by hanging out the get semaphore, and the data is readable.


many times semaphores and mutexes, conditional variables can be used in some applications, what are the differences between these three, the following list of the differences between the three : the mutex must be locked by the line threads unlocked. The semaphore does not need to be hung by the thread waiting for it, and can be hung out in another process. The mutex is either locked or untied, with only two states. The value of a semaphore can support multiple processes succeeding in a wait operation. The semaphore's hang out operation is always remembered, because the semaphore has a count value, the hang out operation will always add the count value of 1, but when sending a signal to the condition variable, if there is no thread waiting in the condition variable, then the signal will be lost.


2 POSIX semaphore function interface



The function interface of the POSIX semaphore is shown in the following illustration:




2.1 The creation and deletion of famous semaphores





#include <semaphore.h>

sem_t *sem_open (const char *name, int oflag);
sem_t *sem_open (const char *name, int oflag,
                  mode_t mode, unsigned int value);
                              Successfully returned semaphore pointer, failed to return sem_failed





Sem_open is used to create or open a semaphore that is identified by the name parameter, the semaphore. The name of the POSX IPC can be referenced in UNIX Network programming Volume 2: interprocess communication P14.



The oflag parameter can be: 0,O_CREAT,O_EXCL. If 0 indicates that an existing semaphore is opened, if it is o_creat, a semaphore is created if the semaphore does not exist and is returned if it exists. mode and value need to be specified at this time. If for o_creat | O_excl, which indicates that an error will be returned if the semaphore already exists.



When the mode parameter is used to create semaphores, the permission bits that represent semaphores are included, as in the Open function: S_irusr,s_iwusr,s_irgrp,s_iwgrp,s_iroth,s_iwoth.



value represents the initial value of the semaphore when the semaphore is created.





#include <semaphore.h>

int sem_close (sem_t *sem);
int Sem_unlink (const char *name);
                              Successfully returned 0, failure returned-1


Sem_close is used to turn off the open semaphore. When a process terminates, the kernel automatically performs this operation on all known semaphores that are still open on it. The call to Sem_close turns off the semaphore and does not remove it from the system, and POSIX-named semaphores are persisted with the kernel. The value remains if no process is currently opening a semaphore. Until the kernel restarts or calls Sem_unlink () to remove the semaphore.



Sem_unlink is used to remove a well-known semaphore from the system immediately, but the semaphore is destroyed when all processes turn off the semaphore. 


2.2 The P operation of the semaphore





#include <semaphore.h>

int sem_wait (sem_t *sem);

#ifdef __use_xopen2k
int sem_timedwait (sem_t *sem, const struct TIMESPEC);
#endif

int sem_trywait (sem_t * sem);
                              Successfully returned 0, failure returned-1
Sem_wait () is used to get the semaphore, first test the value of the specified semaphore, if greater than 0, it will be reduced by 1 and immediately return, if equal to 0, then the calling thread will go to sleep, the specified semaphore value is greater than 0.





The difference between sem_trywait and sem_wait is that when the semaphore value equals 0, the calling thread does not block, returns directly, and identifies the Eagain error.



The difference between sem_timedwait and sem_wait is that when the value of the semaphore equals 0 o'clock, the calling thread waits for a limited time. When the wait time is up, the semaphore value is 0, and an error is returned. Where the struct Timespec *abs_timeout is an absolute time, can refer to the conditional variable about the waiting time using the V-operation of the 


2.3 semaphore


#include <semaphore.h>

int sem_post (sem_t *sem);
                            Successfully returned 0, failure returned-1


When a thread finishes using a semaphore, call Sem_post to add a value of 1 to the semaphore, and if there is a waiting thread, it wakes up a waiting thread. 


2.4 Get the value of the current semaphore


#include <semaphore.h>

int sem_getvalue (sem_t *sem,  int *sval);
                            Successfully returned 0, failure returned-1


The function returns the value of the current semaphore, returned by the Sval output parameter, if the current semaphore is already locked (that is, the synchronization object is not available), the return value is 0, or is a negative number, with the absolute amount of the thread waiting for the semaphore to unlock.



Here is a test to see if there is a negative amount of semaphore under Linux:


#include <iostream>

#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h >

using namespace std;

#define SEM_NAME "/sem_name"

sem_t *psem;

void * Testthread (void *ptr)
{
    sem_wait (psem);
    Sleep (a);
    Sem_close (Psem);
}

int main ()
{
    Psem = Sem_open (Sem_name, O_creat, 0666, 5);

    pthread_t pid;
    int semval;

    for (int i = 0; i < 7; ++i)
    {
        pthread_create (&pid, NULL, testthread, NULL);

        Sleep (1);

        Sem_getvalue (Psem, &semval); 
        cout<< "semaphore value:" <<semVal<<endl;
    }

    Sem_close (Psem);
    Sem_unlink (Sem_name);
}


The results of the implementation are as follows:


Semaphore Value:4
Semaphore value:3
semaphore value:2
semaphore value:1 Semaphore value:0 Semaphore value:0
Semaphore value:0


This shows that there is no negative value for POSIX semaphores in Linux 2.6.18. 



2.5 creation and destruction of nameless semaphores





#include <semaphore.h>

int sem_init (sem_t *sem, int pshared, unsigned int value);
                            If an error returns-1
int Sem_destroy (sem_t *sem);
                            Successfully returned 0, failure returned-1





Sem_init () is used for initialization of nameless semaphores. Unknown semaphore before initialization, be sure to allocate a sem_t Semaphore type object in memory, which is why the nameless semaphore is also called the memory based semaphore.



Sem_init () The first argument is to point to an already allocated sem_t variable. The second parameter, pshared, indicates whether the semaphore is a step through the process, and when pshared = 0, the semaphore can only be used for synchronization between threads within the process. When pshared!= 0, the semaphore is stored in a shared memory area so that the process using it can access the shared memory area for process synchronization. The third parameter value represents the initial value of the semaphore.



It should be noted here that the nameless semaphore does not use any o_creat-like flag, which means that sem_init () always initializes the semaphore value, so for a particular semaphore, we must ensure that only sem_init () is initialized once, The behavior of an initialized semaphore call Sem_init () is undefined . If the semaphore has not been invoked by a thread, it will basically cause problems.



After using a nameless semaphore, call Sem_destroy to destroy it. Note here: The behavior of destroying the semaphore on which a wire is blocked is undefined. 2.6 Persistence of well-known and nameless semaphores



a known semaphore is persisted with the kernel . When a named semaphore is created, its value remains even if no process is currently opening a semaphore. Until the kernel restarts or calls Sem_unlink () to remove the semaphore.



The persistence of nameless semaphores depends on the location of the semaphore in memory: If the nameless semaphore is in the data space within a single process , that is, the semaphore can only be shared among the threads within the process, the semaphore is continuous with the process , and it disappears when the process terminates. If the nameless semaphore is in a shared memory area of a different process , the semaphore persists as long as the shared memory area is still present. So at this time the nameless semaphore is with the continuity of the kernel . 2.7 The succession and destruction of semaphores



(1) Inheritance



Any well-known semaphore that is opened in the parent process is still open in the child process for the named semaphore. That is, the following code is correct:


sem_t *psem;
Psem = Sem_open (Sem_name, O_creat, 0666, 5);

if (fork () = = 0)
{
    //...
    Sem_wait (Psem);
    //...
}


Inheritance of nameless semaphores depends on the position of the semaphore in memory: If the unknown semaphore is in the data space within a single process , then the semaphore is the process data segment or the stack, and when fork produces the subprocess, the semaphore is only a copy of the original. And before the semaphore is independent. Here is the test code:





int main ()
{
    sem_t msem;
    Sem_init (&msem, 0, 3);

    int Val;
    Sem_getvalue (&msem, &val);
    cout<< "Parent:semaphore value:" <<val<<endl;

    Sem_wait (&msem);
    Sem_getvalue (&msem, &val);
    cout<< "Parent:semaphore value:" <<val<<endl;

    if (fork () = = 0)
    {   
        sem_getvalue (&msem, &val);
        cout<< "Child:semaphore value:" <<val<<endl;  

        Sem_wait (&msem);

        Sem_getvalue (&msem, &val);
        cout<< "Child:semaphore value:" <<val<<endl;

        Exit (0);
    }
    Sleep (1);

    Sem_getvalue (&msem, &val);
    cout<< "Parent:semaphore value:" <<val<<endl;
}





The test results are as follows:


Parent:semaphore value:3
parent:semaphore value:2
child:semaphore value:2 child:semaphore value:1
Parent:semaphore Value:2
If the unknown semaphore is in shared memory area for different processes, the semaphore in the child process generated by fork still exists in the shared memory area, so the semaphore remains in its previous state.


(2) Destruction



For a well-known semaphore , when a process holding the semaphore terminates without unlocking the semaphore, the kernel does not unlock the semaphore. This is not the same as the record lock.



For nameless semaphores , if the semaphore is in the memory space inside the process, when the process terminates, the semaphore does not exist, it does not matter unlocked. If the semaphore is in a shared memory area between processes, the kernel will not unlock the semaphore when the process terminates.



Here is the test code:


int main ()
{
    sem_t *psem;
    Psem = Sem_open (Sem_name, O_creat, 0666, 5);

    int Val;
    Sem_getvalue (Psem, &val);
    cout<< "Parent:semaphore value:" <<val<<endl;   

    if (fork () = = 0)
    {   
        sem_wait (psem);
        Sem_getvalue (Psem, &val);
        cout<< "Child:semaphore value:" <<val<<endl;

        Exit (0);
    }
    Sleep (1);

    Sem_getvalue (Psem, &val);
    cout<< "Parent:semaphore value:" <<val<<endl;

    Sem_unlink (Sem_name);
}


Here is the test result:


Parent:semaphore value:5
child:semaphore value:4
parent:semaphore value:4
2.8 Semaphore Code Test


Any well-known semaphore that is opened in the parent process is still open in the child process for the named semaphore. That is, the following code is correct:



For testing the code that semaphores use for interprocess synchronization, I did not use the classic producer and consumer issues because it involves the operation of shared memory. I'm simply describing it as an example of a synchronized file operation. In the following test code, the POSIX well-known semaphore initial value is 2, allowing two processes to obtain file operation permissions. The code is as follows:


#include <iostream>
#include <fstream>
#include <cstdlib>

#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>

using namespace std;

#define SEM_NAME "/sem_name"

void semtest (int flag)
{ 
    sem_t *psem;
    Psem = Sem_open (Sem_name, O_creat, 0666, 2);

    Sem_wait (Psem);

    Ofstream FileStream ("./test.txt", Ios_base::app);  

    for (int i = 0; i < 5; ++i)  
    {sleep  
        (1);  

        filestream<<flag;  
        filestream<< ' <<flush;  
    }  

    Sem_post (Psem);
    Sem_close (Psem);
}

int main ()
{for
   (int i = 1; I <= 3; ++i)
   {
       if (fork () = 0)
       {
           semtest (i);

           Sleep (1);
           Exit (0);}}}


The operating results of the program, the contents of the "./test.txt" file are as follows:


./test.txt
1 2 1 2 1 2 1 2 1 2 3 3 3 3 3   


June 1, 2013 PM 22:04 @dorm



The following topics:



Blink of an eye to July, according to the plan before, I should now do what I want to do, but always backfired, indeed a lot of factors are their own reasons, ah, bitter force ah ... can only read more books, September to find a good job, I hope the summer vacation is not a mess of things to worry about ...



Today is the birthday of sister Sally, Brother here wish you happy birthday, although not together to help you have a birthday, or hope you are happy every day, more and more beautiful, love sweet honey ... < ^_^ >


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.