Semaphores in Linux page 4

312阅读 0评论2008-12-12 futuregod
分类:LINUX

NOTE: System V semaphores are controlled by the user, but can be a problem to the developer is the permissions on the semaphore. The structure that maintains this information is struct semid_ds.



struct semid_ds
{
struct ipc_perm sem_per; /* operation's permission structure */
struct sem * sem_base; /* pointer to first sem in a set */
ushort sem_nsems; /* number of sem in a set */
time_t sem_otime; /*time of last semop */
time_t sem_ctime; /* time of last change */
};

For every set of semaphores in the system, the kernel maintains a structure of information that is defined in sys/ipc.h. To get the details of the semaphore set shown above, the IPC_STAT flag is used and a pointer to structure semid_ds is passed. The member variable that gets and sets the permissions is sem_per. Let's see a simple example:

#include 
#include
#include
#include

int main()
{
int semid;
struct semid_ds status;

semid = semget(( key_t )0x20,10,IPC_CREAT|0666);
if(semid == -1)
{
perror("sem creation failed:Reason");
exit(0);
}
//get the permission details
semctl(semid,0,IPC_STAT,&status);
printf("owners uid is %u\n",status.sem_perm.uid);
printf("group uid is %u\n",status.sem_perm.gid);
printf("Access mode is %c\n",status.sem_perm.mode);

//set the permissions details
status.sem_perm.uid = 102;
status.sem_perm.gid = 102;
status.sem_perm.mode = 0444;
semctl(semid,0,IPC_SET,&status);

return 1;
}

Note that the setting of permission is only allowed if the new permission set is a subset of the original permission, and not a superset.

POSIX Semaphores

The potential learning curve of System V semaphores is much higher when compared to POSIX semaphores. This will be more understandable after you go through this section and compare it to what you learned in the previous section.

To start with, POSIX comes with simple semantics for creating, initializing, and performing operations on semaphores. They provide an efficient way to handle interprocess communication. POSIX comes with two kinds of semaphores: named and unnamed semaphores.

Named Semaphores

If you look in the man pages, you'll see that a named semaphore is identified by a name, like a System V semaphore, and, similarly, the semaphores have kernel persistence. 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.

A named semaphore is created by calling following function:

sem_t *sem_open(const char *name,  int oflag, mode_t mode , int value);
name
Name of the semaphore to be identified.
oflag
Is set to O_CREAT for creating a semaphore (or with O_EXCL if you want the call to fail if it already exists).
mode_t
Controls the permission setting for new semaphores.
value
Specifies the initial value of the semaphore.

A single call creates the semaphore, initializes it, and sets permissions on it, which is quite different from the way System V semaphores act. It is much cleaner and more atomic in nature. Another difference is that the System V semaphore identifies itself by means of type int (similar to a fd returned from open()), whereas the sem_open function returns type sem_t, which acts as an identifier for the POSIX semaphores.

From here on, operations will only be performed on semaphores. The semantics for locking semaphores is:

int  sem_wait(sem_t *sem);

This call locks the semaphore if the semaphore count is greater than zero. After locking the semaphore, the count is reduced by 1. If the semaphore count is zero, the call blocks.

The semantics for unlocking a semaphore is:

int  sem_post(sem_t *sem);

This call increases the semaphore count by 1 and then returns.

Once you're done using a semaphore, it is important to destroy it. To do this, make sure that all the references to the named semaphore are closed by calling the sem_close() function, then just before the exit or within the exit handler call sem_unlink() to remove the semaphore from the system. Note that sem_unlink() would not have any effect if any of the processes or threads reference the semaphore.

Unnamed Semaphores

Again, according to the man pages, an unnamed 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 a region where only threads of an process share them, for example a global variable. A process-shared semaphore is placed in a region where different processes can share them, for example something like a shared memory region. An unnamed semaphore provides synchronization between threads and between related processes and are process-based semaphores.

The unnamed semaphore does not need to use the sem_open call. Instead this one call is replaced by the following two instructions:

{
sem_t semid;
int sem_init(sem_t *sem, int pshared, unsigned value);
}
pshared
This argument indicates whether this semaphore is to be shared between the threads of a process or between processes. If pshared has value 0, then the semaphore is shared between the threads of a process. If pshared is non-zero, then the semaphore is shared between processes.
value
The value with which the semaphore is to be initialized.

Once the semaphore is initialized, the programmer is ready to operate on the semaphore, which is of type sem_t. The operations to lock and unlock the semaphore remains as shown previously: sem_wait(sem_t *sem) and sem_post(sem_t *sem). To delete a unnamed semaphore, just call the sem_destroy function.

The last section of this article has a simple worker-consumer demo that has been developed by using a POSIX semaphore.

System V Semaphores versus POSIX Semaphores

There are a number of differences between System V and POSIX semaphores.

上一篇:Semaphores in Linux page 3
下一篇:Semaphores in Linux page 5