POSIX semaphore

    The XSI standard semaphores are mentioned in the Semaphore section of XSI IPC communication . POSIX semaphores are intended to address the following shortcomings of XSI semaphores.
    1) POSIX semaphores allow for higher performance implementations.
    2) The POSIX semaphore interface is simpler to use: there is no semaphore set.
    3) POSIX semaphores behave more perfectly when deleted. When an XSI semaphore is removed, operations using the semaphore identifier fail with errno set to EIDRM. With POSIX semaphores, operations continue to work normally until the last reference to the semaphore is released.
    There are two types of POSIX semaphores, named and unnamed. The difference is in the form of creation and destruction. Named semaphores can be used by threads in any process whose name is known. Unnamed semaphores, on the other hand, exist only in memory, which means they can only be applied to threads in the same process, or threads in different processes that have mapped the same memory contents into their address space.
    You can use the sem_open function to create a new named semaphore or use an existing semaphore. The semaphore pointer returned by this function is used to pass to other semaphore functions. When the semaphore operation is complete, the sem_close function can be called to release any semaphore-related resources. The sme_unlink function can be used to destroy a named semaphore.
#include <semaphore.h>
sem_t * sem_open (const char * name, int oflag, ... / * mode_t mode, unsigned int value * /);
              /* Return value: If successful, return a pointer to the semaphore; if error, return SEM_FAILED */
int sem_close (sem_t * sem);
int sem_unlink(const char *name);
                           /* The return value of the two functions: if successful, return 0; otherwise, return -1 */

    In the sem_open function, when using an existing named semaphore, only the first two parameters need to be specified: the name of the semaphore and the 0 value of oflag. When the oflag parameter has the O_CREAT flag, the named semaphore is created if it does not exist. If it already exists, it will be used, but no additional initialization will take place. The last two additional parameters are required when specifying the O_CREAT flag. The mode parameter specifies the permission to use the semaphore, and its value is the same as the permission bit of the file. The permissions assigned to the semaphore can be modified by the caller's file creation mask. Another parameter value specifies the initial value of the semaphore, and its value range is: 0 ~ SEM_VALUE_MAX (see the section on unix restrictions ). If you want to ensure that the semaphore is created, you can set the oflag parameter to O_CREAT|O_EXCL. This will cause the sem_open function to fail with errno set to EEXIST if the semaphore already exists.
    To increase portability, the following rules must be followed when naming semaphores.
    1) The first character of the name should be "/" to disambiguate the name when the POSIX semaphore implementation uses the file system.
    2) Names should not contain extra slashes to avoid implementation-defined behavior. For example, /mysem and //mysem would be considered the same filename if the filesystem was used, but they could be considered different if not.
    3) The maximum length of a semaphore name is implementation-defined and should not be longer than _POSIX_NAME_MAX characters, as this is the maximum name length allowed by an implementation using the file system.
    If the process exits without calling the sem_close function, the kernel will automatically close any open semaphores. Note that this does not affect the state of the semaphore value - if it has already been incremented, this will not change on exit. Similarly, the semaphore value will not be affected by calling the sem_close function.
    The sem_unlink function removes the semaphore name. Destroys immediately if there are no open semaphore references. Otherwise, destruction will be delayed until the last open reference is closed.

    When you want to use a POSIX semaphore within a single process, it is easier to use an unnamed semaphore. This just requires changing the way semaphores are created and destroyed compared to named semaphores.
    The sem_init function can be called to create an unnamed semaphore. When the use of the unnamed semaphore is complete, the sem_destroy function can be called to discard it.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy (sem_t * sem);
                           /* The return value of the two functions: if successful, return 0; otherwise, return -1 */

    When the pshared parameter in the sem_init function is a non-zero value, it means that the semaphore can be used in multiple processes. The value parameter specifies the initial value of the semaphore. The sem parameter represents the address of the anonymous semaphore. If you want to use a semaphore between multiple processes, you need to make sure that the parameter is within the memory range they share.
    After calling the sme_destroy function, you can no longer use any semaphore functions with sem unless the sem_init function is called to reinitialize it.

    After the semaphore is created, you can use the following functions to operate. Among them, the sem_wait or sem_trywait function can be used to reduce the semaphore by 1. The sem_timedwait function can optionally block for a certain amount of time. The sem_post function can be used to increment the semaphore value by one. The sem_getvalue function can be used to retrieve the semaphore value (this function is not supported on Mac OS X 10.6.8).
#include <semaphore.h>
int sem_wait (sem_t * sem);
int sem_rywait (sem_t * sem);
int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict tsptr);
int sem_post (sem_t * sem);
int sem_getvalue(sem_t *restrict sem, int *restrict valp);
                           /* Return values ​​of several functions: if successful, return 0; otherwise, return -1 */

    When using the sem_wait function, if the semaphore count is 0, it will block and will not return until the semaphore is successfully decremented by 1 or interrupted by a signal. Use sem_trywait to avoid blocking: if the semaphore is 0, it does not block, but immediately returns -1 and sets errno to EAGAIN. The tsptr parameter in the sem_timedwait function can specify absolute time (based on the CLOCK_REALTIME clock). If the timeout expires and the semaphore count fails to decrease by 1, the function returns -1 and sets errno to ETIMEDOUT.
    Calling sem_post can wake up one of the processes blocked by calling functions such as sem_wait, and the semaphore count incremented by 1 by sem_post will be decremented by 1 again by functions such as sem_wait.
    After the sem_getvalue function is called successfully, the valp parameter will contain the semaphore value. Note, however, that the value of the semaphore may have changed after the value is read. This function should only be used for debugging unless additional synchronization mechanisms are used to avoid this race.
    The following code uses POSIX semaphores to implement a lock that can be locked by one thread and unlocked by another thread.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

struct slock{
	sem_t *sem;
	char	name[_POSIX_NAME_MAX];
};

struct slock* s_alloc(){
	struct slock	*sp;
	static int		cnt;
	if((sp=malloc(sizeof(struct slock))) == NULL)
		return NULL;
	do{
		snprintf(sp->name, sizeof(sp->name), "/%ld.%d", (long)getpid(), cnt++);
		sp->semp = sem_open(sp->name, O_CREAT|O_EXCL, S_IRWXU, 1);
	}while(sp->semp == SEM_FAILED && errno == EEXIST);
	if(sp->semp == SEM_FAILED){
		free(sp);
		return NULL;
	}
	sem_unlink(sp->name);
	return sp;
}

void s_free(struct slock *sp){
	sem_close(sp->semp);
	free(sp);
}

int s_lock(struct slock *sp){
	return sem_wait(sp->semp);
}

int s_trylock(struct slock *sp){
	return sem_trywait(sp->semp);
}

int s_unlock(struct slock *sp){
	return sem_post(sp->semp);
}

    Here the name is created based on the process ID and counter. Note that there is no need to protect the counter with a mutex, because when two competing threads call s_alloc at the same time and end up with the same name, using the O_EXCL flag in the call to sem_open will make one succeed and the other fail, failing 's thread will set errno to EEXIST and will try again. Also, opening a semaphore in the s_alloc function and then disconnecting it destroys the name so other processes cannot access it again, and also simplifies cleanup when the process ends.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325994135&siteId=291194637