WordPress.com



5.4 semaphores

Assume that two process for accessing the same file. The one that got the time slice first would initialize a variable before working on the file. When the other process is given that time slice would first check the value of this variable realize it has been initialize by some other process and refrain from the accessing the file. When the first process finished it would reinitialize this variable. As a result the second process which has been waiting for just this to happen will get access to the file.

The variable in Linux terms is known as Semaphore and is an integer, which acts as a counter. Its value depends on the number of resources there are crucial. For example if we had one file which is to be shared then semaphore can have a value 0 or 1. A zero initialize semaphore signifies that the resource in this case the file is in used. and therefore all other process would have to wait. In the moment the process that has access to the file finishes it sets the semaphore value to one. Thereby allowing one other process access .

There are two aspects of semaphores – one is that they can be used to restrict two processes from accessing the same file simultaneously and two they help in resource synchronization.

Several processes are accessing the shared variable to get the least value, read it, increment it, and then save it back to the critical section. But there is one problem here. what if after a process read a value its time slice got over. As a result another process which access this value would see the same value. And this is of course would lead to a lot of confusion with values being repeated every time a break like this occurs in time slices. These three lines of code that checks the value in critical section, increment it and saves it back is known in linux jargon as CRITICAL REGION. Because it is critical that these lines of code are performed together else confusion is bound to occur.

x = criticalsectionvalue;

x = x+1;

criticalsectionvalue = x;

However since this critical section is not a file, a lock() or fcntl() cant’t be performed to prevent this happening. And that is where the concept of semaphore comes in.

A binary semaphore: A semaphore whose value is zero or one. In which the semaphore value is zero if the resource is locked, or one the resource is avilable.

A Counting semaphore: A semaphore whose value is between zero and some limit.

A set of Counting Semaphores: one or more semaphores(A set), each of which is a counting semaphore . There is a limit to the number of semaphores for set, typically on the order of 25 semaphores.

5.4.1 Semaphore Structures

For every set of semaphores in the system, the kernel maintains a structure of information. The structure name is semid_ds, and is defined in the sys/ipc.h header file.

struct smid_ds

{

struct ipc_perm sem_perm; /* operation permission structure */

struct sem * sem_base; /* prt to first sema in set */

ushort sem_nsems; /* no of sema is set */

time_t sem_otime; /* time of last semop() */

time_t sem_ctime; /* time of last change */

};

The sem_base pointer is worthless to a user process, since it point to memory in the kernel. What it points to is an array of sem structures, containing sem_nsems elements, one elements in the array for each semaphore value in the set.

struct sem {

unshort semval; /* semaphore value always >= 0 */

pid_t sempid; /* pid for last operation */

ushort semncnt; /* #proceses awaiting semval > currval */

ushort semzcnt; /* # processes awaiting semval = 0 */

};

5.4.2 Creating a Semaphore

The semget() system call returns the semaphore set identifier associated with the argument key.

#include

#include .

#include

int semget((key_t)key, int nsems, int flag);

Returns: Non negative identifier if OK, -1 on error.

The return value is an integer called the semaphore identifier that is used with the semop() and semctl() functions.

The variable key takes hexadecimal values, if decimal value is given it will be converted to hexa decimal value. To assign a hexadecimal value 0x20, key = 0X20, this is the name that we create the semaphore.

The nsem argument specifies the number of sub semaphores in the set. If we are not creating a new semaphore set but just accessing an existing set, we can specify this argument as 0. We can not change the number of semaphores in a set once it is created. When we assign a 0 to nsem which is below the minimum required. As a result an error is returned.

Flag is a combination of read-write permission. This can be bitwise-Ored with either IPC_CREAT or IPC_CREAT | IPC_EXCL.

And flag which can be one of the following:

IPC_CREAT: which means that the semaphore is to be created if it does not exist and “ID” of semaphore is returned. If the semaphore is already exists with that key, only it's “ID” is returned.

IPC_EXCL alone does not have any meaning. It should be used along with IPC_CREAT only. IPC_CREAT | IPC_EXCL forces an error when a queue already exists other wise it creates message queue and returns its “ID”.

Specifying a key of IPC_PRIVATE guarantees that unique IPC object is created.

4) Permissions are ORed wirh one of the above three values. For example, IPC_CREAT | 0642, user will get read and write permissions, group will get read permission and others will get write permission.

When a new semaphore set is created, the following members of the semid_ds structure are initialized:

1)The uid and cuid members of the sem_perm structure are set to the effective user ID of the classes, and the gid and cgid members are set to the effective group id of the process.

2)The read-write permission bits in flag are stored in sem_prm.mode.

3)sem_otime is set to zero and sem_ctime is set to current time.

4)Sem_nsems is set to nsems.

5)The sem structure associates with each semaphore in the set is not initialized. These structures are initialized when semctl is called with either the SETVAL are SESTALL commands.

To see the list of semaphores already existing in the system. We can use the command ipcs –s at the command prompt.

/* 1)Create a semaphore (sem.c)

*/

#include

#include

#include

#include

int main()

{

int semid,nsem=1;

key_t key=1;

semid = semget(key,nsem,IPC_CREAT | 0666);

if(semid < 0)

perror("Failed To create Semaphore");

else

printf("semid is %d \n",semid);

}

OUTPUT

Semaphore is Successfully Created and its ID is 360451

ipcs -s

------ Semaphore Arrays --------

key semid owner perms nsems

0x00000001 360451 user 666 1

5.4.3 semctl() : Semaphore Control Operations

#include

#include

#include

int semctl(int semid, int semnum, int cmd, ...);

return : non negative value if OK, -1 on error. The system call returns a non-negative value depending on cmd as follows:

GETNCNT the value of semncnt.

GETPID the value of sempid.

GETVAL the value of semval.

GETZCNT the value of semzcnt.

semctl() performs the control operation specified by cmd on the semaphore set identified by semid.

This function has three or four arguments, depending on cmd.

First parameter: The ID of the semaphore,which is returned by semget() function.

Second parameter: Identifies the member of the semaphore set ( 0, 1, and so on up to

nsem–1 ). The semnum value is used only for the GETVAL, SETVAL, GETCNT, GETZCNT, and GETPID commands.

Third parameter:

IPC_RMID - to remove semaphore, for this 2nd and 4th parameters are zeros for e.g, semctl( semid, 0, IPC_RMID,0);

SETVAL: semctl() funtion can be used to set the semaphore value. We can assign only integer values. For e.g, semctl( semid, 2, SETVAL,5); The second sub semaphore pointed by semid will be set to the value 5. The calling process must have alter permission on the semaphore set.

GETVAL returns the current value of semval as the return value of the function. Since the semaphore value is a never negative, a successful return value is always non negative. For this 4th parameter is zero. for e.g, ret = semctl( semid, 2, GETVAL,0); on Success it returns 5. The calling process must have read permission on the semaphore set.

SETALLL: semctl() funtion can be used to set the semaphore values. We can assign only integer values. For e.g, semctl( semid, 0, SETALL,values1); It updates all values of semaphore pointed by semid with the argument array values1. The argument semnum is ignored. The calling process must have alter permission on the semaphore set.

GETALLL: semctl() funtion can be used to get the semaphore values. for e.g, semctl( semid, 0, SETALL,values1); Return semval (i.e., the current value) for all semaphores of the set into arg.array(values1).The argument semnum is ignored.The calling process must have read permission on the semaphore set.

GETZCNT : For e.g, val = semcntl(semid,2,GETZCNT,0); The system call returns the value of semzcnt, for the 2nd sub semaphore of the set. The calling process must have read permission on the semaphore set.

GETNCNT : for e.g, val = semcntl(semid,2,GETNCNT,0); The system call returns the value of semncnt for the 2nd sub semaphore of the set. The calling process must have read permission on the semaphore set.

GETPID The system call returns the value of sempid for the semnum-th semaphore of the set (i.e., the PID of the process that executed the last semop(2) call for the semnum-th semaphore of the set). The calling process must have read permission on the semaphore set.

IPC_STAT Copy information from the kernel data structure associated with semid into the semid_ds structure pointed to by arg.buf. The argument semnum is ignored. The calling process must have read permission on the semaphore set.

IPC_SET Write the values of some members of the semid_ds structure pointed to by arg.buf to the kernel data structure associated with this semaphore set.

The following members of the structure are updated:

sem_perm.uid, sem_perm.gid, and sem_perm.mode.

The caller must be privileged. The argument semnum is ignored.

Fourth parameter: The fourth argument is optional, depending upon the cmd. When required, it is the following union:

Union semnum {

int val; /* used for SETVAL only */

struct semid_ds buff; /* used for IPC_SET and IPC_STAT */

ushort array ; /* used for GETALL and SETALL */

};

The actual value of the union is the argument, not a pointer to the union.

/* A program on semctl() sem_getset.c

*/

#include

#include

#include

#include

int main()

{

int semid,val;

key_t key=100;

semid = semget(key,4,IPC_CREAT | 0666);

printf("semid is %d \n",semid);

/* Demonstration of SETVAL & GETVAL */

semctl(semid,0,SETVAL,2);

val=semctl(semid,0,GETVAL,0);

printf("SETVAL & GETVAL semaphore Value %d \n",val);

}

OUTPUT:

semid is 32769

SETVAL & GETVAL semaphore Value 2

/* A program on semctl() sem_GETSETALL.c

*/

#include

#include

#include

#include

int main()

{

int semid,pid,val;

struct sembuf sop;

struct semid_ds semstat;

key_t key=100;

ushort values[4],values1[]={8,9,10,11};

semid = semget(key,4,IPC_CREAT | 0666);

printf("semid is %d \n",semid);

/* Demonstration of GETALL */

semctl(semid,0,SETVAL,2);

semctl(semid,1,SETVAL,3);

semctl(semid,2,SETVAL,4);

semctl(semid,3,SETVAL,5);

semctl(semid,0,GETALL,values);

printf("Semaphore Values %u %u %u %u \n", values[0],values[1],values[2],values[3]);

/* Demonstration of SETALL */

semctl(semid,0,SETALL,values1);

semctl(semid,0,GETALL,values);

printf("Semaphore Values using SETALL & GETALL %u %u %u %u \n", values[0],values[1],values[2],values[3]);

}

OUTPUT:

semid is 32769

Semaphore Values 2 3 4 5

Semaphore Values using SETALL & GETALL 8 9 10 11

/* A program on semctl() sem_IPCSTAT.c

*/

#include

#include

#include

#include

int main()

{

int semid,pid,val;

struct semid_ds semstat;

key_t key=100;

semid = semget(key,4,IPC_CREAT | 0666);

printf("semid is %d \n",semid);

/* Demonstration of GETNCNT */

val=semctl(semid,0,GETNCNT,2);

printf("GETNCNT, semncnt Value %d \n",val);

/* Demonstration of GETZCNT */

val=semctl(semid,0,GETZCNT,2);

printf("GETZCNT, semzcnt Value %d \n",val);

/* Demonstration of IPC_STAT */

val=semctl(semid,0,IPC_STAT,&semstat);

if(val == 0)

{

printf("Semaphore STAT is SUCCEESS \n");

printf("Number of sub semaphores %d \n", semstat.sem_nsems);

printf("Time of Last Change %s \n", ctime(&semstat.sem_ctime));

}

else

perror("IPC_STAT Failed in Semaphore");

}

OUTPUT:

semid is 32769

GETNCNT, semncnt Value 0

GETZCNT, semzcnt Value 0

Semaphore STAT is SUCCEESS

Number of sub semaphores 4

Time of Last Change Mon Mar 4 00:15:57 2013

/* A program on semctl() sem_IPCRMID.c

*/

#include

#include

#include

#include

int main()

{

int semid,val;

key_t key=100;

semid = semget(key,4,IPC_CREAT | 0666);

printf("semid is %d \n",semid);

val=semctl(semid,0,IPC_RMID,0);

if(val == 0)

printf("Semaphore is Deleted \n");

else

perror("Failed To Delete Semaphore");

}

OUTPUT:

semid is 32769

Semaphore is Deleted

SEMOP: Semaphore Operation

#include

#include

#include

int semop(int semid, struct sembuf *sops, unsigned nsops);

RETURN VALUES:

on success return 0; otherwise they return -1

semid : semaphore ID returned by semget() function for a given key.

nsops : Number sub semaphores;0 for first sub semaphore, 1 for second semaphore and so on.

semop() performs operations on selected semaphores in the set indicated by semid. The elements of this structure are of type struct sembuf, containing the following members:

struct sembuf{

ushort sem_num; /* sub semaphore number, 0 for first, 1 for second sub sema and so on. */

short sem_op; /* semaphore operation +VE, -VE , or ZERO */

short sem_flg; /* operation flags; IPC_NOWAIT,0 and SEM_UNDO */

};

sem_num is the number that is associated with a sub-semaphore. 0 indicates the first sub-semaphore, 1 for second sub semaphore and so on.9

sem_op is a value that defines the operation we want to perform on the sub semaphore.

If sem_op is +ve means releasing of resources i.e sem_op value is added to semval.

If sem_op is -ve means requesting for resources i.e sem_op value is subtracted to semval.

If sem_op is 0 this means we want to wait until the semaphore’s value becomes 0.

sem_flg : sem_flg = 0 means, if resources are not available process will be blocked.

sem_flg = IPC_NOWAIT means, if resources are not available process will continue.

sem_flg = SEM_UNDO : It will automatically undone when the process terminates.

1)If sem_op is +ve : This corresponds to the returning of resources by the process. The value of sem_op is added to the semaphore's value.

2)If sem_op is -ve : This corresponds to the requesting for the resources by the process.

a)If sem_op is -ve and semval >= |sem_op | means resources are available.

|If semval >= | sem_op | |

|If semaphore's value greater than or equal to absolute value of sem_op (resources are available ). The absolute value of sem_op is subtracted from |

|semaphore's value. |

| |

|semval = semval - | sem_op | |

|For e.g, semval = 3 and sem_op = -2 after semop() function semval will become to 1. |

b)If sem_op is -ve and semval < |sem_op | means resources are not available. The action of function semop() depend on the value of sem_flg.

|If sem_flg = IPC_NOWAIT |If sem_flg =0 |

|If semval < | sem_op| and sem_flg = IPC_NOWAIT, function returns |The semncnt (no of processes waiting on that sub semaphore) value for |

|immediately. |this sub semaphore is incremented and calling process is suspended until |

|For e.g, semval = 1 and sem_op = -2 i.e 1 < |-2|. |one of the following occurs. |

| |i) If semaphore's value becomes greater than or equal to absolute value |

| |of sem_op, the value value of semncnt for this sub semaphore is |

| |decremented by 1, resource are allocated to process and process will be |

| |unblocked. |

| |ii) If semaphore is removed from the system. |

| |Iii) A signal is caught by the process. |

3)If sem_op is 0 this means we want to wait until the semaphore’s value becomes 0.

( semval = 0 means resources are available and semval = 1 resources are not available)

a) if semval is currently zero the function returns immediately.

b)If semval is non zero means resources are not available. The action of function semop() depend on the value of sem_flg.

|If sem_flg = IPC_NOWAIT |If sem_flg =0 |

|If semval is non zero < and sem_flg = IPC_NOWAIT, function returns |The semzcnt (no of processes waiting on that sub semaphore) value for |

|immediately. |this sub semaphore is incremented and calling process is suspended until |

| |one of the following occurs. |

| |i) If semaphore's value becomes to zero, the value value of semzcnt |

| |for this sub semaphore is decremented by 1, resource are allocated to |

| |process and process will be unblocked. |

| |ii) If semaphore is removed from the system. |

| |Iii) A signal is caught by the process. |

Examples :

sem_op is + ve means releasing resources.

semval = 3 ans sem_op = 2: after semop() function semval will become to 5.

semval = 1 and sem_op = 2; after semop() function semval will become to

sem_op is - ve means request for resources.

1) semval = 4 ans sem_op = -3; Available resources are greater than the requested resources so resources are allocated to requested process. After semop(), semval will become to 1.

2) semval =1 and sem_op = -3; Resource are not available.

If sem_flg = IPC_NOWAIT the semop() function will continue without allocating resources.

If sem_flg = 0; the semop() function will block until resources are available.

sem_op is zero means semop() function waits until semval = 0

semval = 0 and sem_op = 0; resource is available, semop() function returns immediately.

Semval is non zero and sem_op = 0; resources are not available.

if sem_flg =IPC_NOWAIT the semop() function will continue without allocating resources.

If sem_flg = 0; the semop() function will block until resources are available.

SEM_UNDO :

Each process has one version of semadj variable. Whenever a semop() operation is applied and sem_flg=SEM_UNDO, the following sequence of events takes place.

1)Before the process starts the value of semadj is set to 0 and semval =2.

2)The value of sem_op is subtracted from that of semadj. The sign of sem_op plays an important role.

If sem_op = 2; semadj = semadj – sem_op;

semadj = 0 – 2 = -2 and semval = sembal + sem_op = 2 = 4

if sem_op = -3 ; semadj = semadj - ( -3)

semadj = -2 -(-3) = 1; and semval = semval - | sem_op| = 4 – 3 = 1.

3)And, finally the value of semadj is added to the value of the sub semaphore. This happens when the process terminates normally or abnormally.

FILE LOCKING :

If one process is using the file no other process is allowed to access the same file. It is called exclusive locking.

To implement file locking:

in first program semaphore value is initialized to one.

Second program can be run on any number of terminals. A process which gets resources access the file all remaining process will be blocked until resource is available.

Program1 : to update semaphore value to one:

#include

#include

#include

#include

int main()

{

int semid,val;

key_t key=11;

semid = semget(key,1,IPC_CREAT | 0666);

printf("semid is %d \n",semid);

semctl(semid,0,SETVAL,1);

val=semctl(semid,0,GETVAL,0);

printf("Parent SET semaphore Value %d \n",val);

}

program2: To acquire resource, to access file and to release resource.

#include

#include

#include

#include

#include

int main()

{

int semid,val,val1;

struct sembuf sop;

key_t key=10;

FILE *fp;

int k,m=10,*a;

semid = semget(key,1,IPC_CREAT | 0666);

if(semid < 0)

perror("semaphore was not created");

/* Requesting for Resources */

/* if resources are not available process will be blocked until resources are available,since sem_flg=0 */

sop.sem_num = 0;

sop.sem_op = -1; /* -ve value Requesting for resources*/

sop.sem_flg =0;

semop(semid,&sop,1);

/* After Successfully acquiring resource, resources will be 0, so no other process get resource(i.e File is locked) */

val=semctl(semid,0,GETVAL,0);

printf("After semop semaphore value %d \n",val);

/*File Opening and modification */

fp = fopen("d1-50","r+");

/* do operation on file */

fclose(fp);

/* After File Close */

/* Releasing Resources */

/* Now another process waiting for resource can access the file */

sop.sem_num = 0;

sop.sem_op = 1; /* +ve value Releasing resources*/

sop.sem_flg =0;

semop(semid,&sop,1);

/* Now Another process can access same file (Lock on file is released)*/

val=semctl(semid,0,GETVAL,0);

printf("After semop()(releasing resources) semaphore value is %d \n",val);

}

}

Sample program on semaphore:

sem_lock.c

/* 1)First run sem1.c program to create semaphore and set its value to 2

* 2)Then run sem3.c program on different terminals at a time

* 3) Requesting for two Resources

* 4)Do some operations on the file

* 5)Only one termial gets resources, other processes will be blocked

* 6)Release the resources, so that other process can modify the file

* 7) EXAMPLE SEM_UNDO

*/

#include

#include

#include

#include

#include

int main()

{

int semid,val,val1;

struct sembuf sop;

key_t key=10;

FILE *fp;

int k,m=10,*a;

semid = semget(key,1,IPC_CREAT | 0666);

if(semid < 0)

perror("semaphore was not created");

for(k=0;k ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download