Link to home
Start Free TrialLog in
Avatar of sudha_sql
sudha_sql

asked on

Semaphore Usage

Hallo All,

Can anyone help to understand the concept & usuage of Semaphore in C language(Windows).

I have a group of people are waiting to cross a bridge. Using semaphore concept, I need to pick a person and put him on the bridge to cross the bridge.

Thanks,


Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image



We can't do your homework for you, but we can nudge you in the right direction.  The link below has a pretty good explanation of semaphores and how to use them.  It's also got sample code that should be quite a bit of help.

http://www.uccs.edu/~compsvcs/doc-cdrom/DOCS/HTML/APS33DTE/DOCU_010.HTM

Good Luck,
Kent
Avatar of SolarinAvon
SolarinAvon

a semaphore is an integer variable whose value can be 0 or 1 (there's a variant that can have multiple values...).

This is an example to help you understanding: suppose you have two programs and you have to print two documents, but you have only one printer. so there's the following situation:  you have to print Document1 with Word and Document2 with Excel. you decide to print the both documents at the same time.

now you need a semaphore:

int sem= 0;

Word checks sem and finds out it is = 0 so he can print and increases sem by 1. now sem = 1.
while Word is printing, also Excel decides to print, so:

Excel checks sem and finds out it is =1, so he knows he can't print and starts waiting. When Word finishes printing he decrements sem by 1 and informs (interrupts) Excel that can continue printing.

this is just an example and it's not the real way printing works, but it's enough to understand.

now consider the following case:

while Word decides to print (cos he discovered SEM=0) and starts incrementing SEM, it's DEscheduled by the OS and Excel is scheduled. Excel does the same Word has just done: checks SEM, he discovers it is = 0, increments it to 1 and starts printing. while he's printing it is descheduled and word is scheduled again.
Word doesn't check SEM again (he already had checked it before being descheduled) and so starts printing too... the result is two documents being printed.

so how can we do to increment or decrement a variable being sure that  the thread incrementing such a variable is not descheduled while doing so? the answer is: using a semaphore.

a semaphore, as said before is just a normal int variable, but it can be incremented and decremented using two system calls: up(int) and down(int). these functions has got the ability not to be descheduled during their operations.

let me know if you wanna know more.
Avatar of sudha_sql

ASKER

I tried to include "#include semaphore.h", I get the following message. Hence the doubt.

 : fatal error C1083: Cannot open include file: 'semaphore.h': No such file or directory
Error executing cl.exe.

Bridges.exe - 1 error(s), 0 warning(s)

Any help?
ASKER CERTIFIED SOLUTION
Avatar of SolarinAvon
SolarinAvon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks a lot, i understood the semaphore concept, but what commands do I use to select a person from a group of people and accquire the lock on that person  when he is crossing the bridge? And how do I release the lock? Any commands like accquire lock will help

thanks
I think we need to use CreateSemaphore right?
from MSDN... tell me if you need the link  

  Platform SDK: DLLs, Processes, and Threads
CreateSemaphore

The CreateSemaphore function creates or opens a named or unnamed semaphore object.


HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  LONG lInitialCount,
  LONG lMaximumCount,
  LPCTSTR lpName
);

Parameters
lpSemaphoreAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpSemaphoreAttributes is NULL, the handle cannot be inherited.
The lpSecurityDescriptor member of the structure specifies a security descriptor for the new semaphore. If lpSemaphoreAttributes is NULL, the semaphore gets a default security descriptor. The ACLs in the default security descriptor for a semaphore come from the primary or impersonation token of the creator.

lInitialCount
[in] Initial count for the semaphore object. This value must be greater than or equal to zero and less than or equal to lMaximumCount. The state of a semaphore is signaled when its count is greater than zero and nonsignaled when it is zero. The count is decreased by one whenever a wait function releases a thread that was waiting for the semaphore. The count is increased by a specified amount by calling the ReleaseSemaphore function.
lMaximumCount
[in] Maximum count for the semaphore object. This value must be greater than zero.
lpName
[in] Pointer to a null-terminated string specifying the name of the semaphore object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.
If lpName matches the name of an existing named semaphore object, this function requests the SEMAPHORE_ALL_ACCESS access right. In this case, the lInitialCount and lMaximumCount parameters are ignored because they have already been set by the creating process. If the lpSemaphoreAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the semaphore object is created without a name.

If lpName matches the name of an existing event, mutex, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.


Terminal Services:  The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces.



Windows XP Home Edition:  Fast user switching is implemented using Terminal Services sessions. The first user to log on uses session 0, the next user to log on uses session 1, and so on. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.



Windows 2000:  If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.



Windows NT 4.0 and earlier:  The name can contain any character except the backslash character.



Windows Me/98/95:  The name can contain any character except the backslash character. The empty string ("") is a valid object name.


Return Values
If the function succeeds, the return value is a handle to the semaphore object. If the named semaphore object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks
The handle returned by CreateSemaphore has the SEMAPHORE_ALL_ACCESS access right and can be used in any function that requires a handle to a semaphore object. For more information, see Synchronization Object Security and Access Rights.

Any thread of the calling process can specify the semaphore-object handle in a call to one of the wait functions. The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a semaphore object is signaled when its count is greater than zero, and nonsignaled when its count is equal to zero. The lInitialCount parameter specifies the initial count. Each time a waiting thread is released because of the semaphore's signaled state, the count of the semaphore is decreased by one. Use the ReleaseSemaphore function to increment a semaphore's count by a specified amount. The count can never be less than zero or greater than the value specified in the lMaximumCount parameter.

Multiple processes can have handles of the same semaphore object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:



A child process created by the CreateProcess function can inherit a handle to a semaphore object if the lpSemaphoreAttributes parameter of CreateSemaphore enabled inheritance.
A process can specify the semaphore-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.
A process can specify the name of a semaphore object in a call to the OpenSemaphore or CreateSemaphore function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.



Windows Me/98/95:  CreateSemaphoreW is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.



Example Code
For an example that uses CreateSemaphore, see Using Semaphore Objects.

Requirements
Client: Included in Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, and Windows 95.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
In the following example, a process uses a semaphore object to limit the number of windows it creates. First, it uses the CreateSemaphore function to create the semaphore and to specify initial and maximum counts.


HANDLE hSemaphore;
LONG cMax = 10;
LONG cPreviousCount;

// Create a semaphore with initial and max. counts of 10.

hSemaphore = CreateSemaphore(
    NULL,   // no security attributes
    cMax,   // initial count
    cMax,   // maximum count
    NULL);  // unnamed semaphore

if (hSemaphore == NULL)
{
    // Check for error.
}
Before any thread of the process creates a new window, it uses the WaitForSingleObject function to determine whether the semaphore's current count permits the creation of additional windows. The wait function's time-out parameter is set to zero, so the function returns immediately if the semaphore is nonsignaled.

DWORD dwWaitResult;
 
// Try to enter the semaphore gate.

dwWaitResult = WaitForSingleObject(
        hSemaphore,   // handle to semaphore
        0L);          // zero-second time-out interval

switch (dwWaitResult)
{
    // The semaphore object was signaled.
    case WAIT_OBJECT_0:
        // OK to open another window.
        break;

    // Semaphore was nonsignaled, so a time-out occurred.
    case WAIT_TIMEOUT:
        // Cannot open another window.
        break;
}
When a thread closes a window, it uses the ReleaseSemaphore function to increment the semaphore's count.

// Increment the count of the semaphore.

if (!ReleaseSemaphore(
        hSemaphore,  // handle to semaphore
        1,           // increase count by one
        NULL) )      // not interested in previous count
{
    // Deal with the error.
}

Thanks once again for the detailed information. But still the basic doubt is that if I great 10 threads, how will I invoke or link those threads or make those threads wait on the semaphore created?

Please let me know

thnaks