Difference between revisions of "Semaphore"

From Xojo Documentation

m (1 revision)
 
(Examples)
 
(24 intermediate revisions by 9 users not shown)
Line 1: Line 1:
 +
{{ClassBox
 +
| super=[[Object]]
 +
| platform=all
 +
| scope=global
 +
}}
 +
{{Description
 +
|text = Used to control access to resources in a multithreaded environment. }}
  
 +
<dynamicTable id="Methods" class="methodTable" title="Methods" columns="2">
 +
{{Method | name=Release | description=Release()&#x0A;Call Release to give a locked resource back to the Semaphore. }}
 +
{{Method | name=Signal | description=Signal()&#x0A;Call Signal to obtain a lock on a resource }}
 +
{{Method | name=TrySignal | returntype=[[Boolean]] | newinversion=2005r1 | description=TrySignal() as Boolean&#x0A;This is a more friendly version of the Signal method that gives you a sneak-peek to determine whether there is a lock available }}
 +
</dynamicTable>
  
=='''Description'''==
 
Used to control access to resources in a multithreaded environment.
 
  
 +
<dynamicTable id="Constructors" class="methodTable" title="Constructors" columns="1">
 +
{{Ctor | params=NumResources as Integer | description=Semaphore(NumResources as Integer)&#x0A; Creates a Semphore instance using the passed number of resources to protect. }}
 +
</dynamicTable>
  
 
+
==Notes==
=='''Super Class'''==
 
[[Object|Object]]
 
 
 
=='''Methods'''==
 
 
 
{| cellpadding="8" cellspacing="0" border="1"
 
 
 
! width=10%  style="background-color:#e0e0e0" | Name
 
 
 
! width=20%  style="background-color:#e0e0e0" | Parameters
 
 
 
! width=25%  style="background-color:#e0e0e0" | Return Type
 
 
 
! width=55%  style="background-color:#e0e0e0" | Description
 
|-
 
|Release
 
 
 
|
 
|
 
|Call Release to give a locked resource back to the Semaphore.
 
You must call Release when you are finished using a locked resource in order to make it available to other requests.
 
 
 
|-
 
|Signal
 
 
 
|
 
|
 
|Call Signal to obtain a lock on a resource. Once you are done with the shared resource, the thread should call Release to increment the internal counter.
 
Every time thread calls Signal, the Semaphore decrements the counter. If the counter is less than zero, it suspends the thread.
 
When you obtain a lock, you can use the resource without fear that another thread will try to use it simultaneously. If the call succeeds, this function returns immediately and you code continues to execute. If the lock is not available, then the thread that called this method will wait until the lock becomes available. When the call returns, you will have the lock, but you may have to wait until the lock becomes available. When you are finished using the resource, call the Release method to give it back to the Semaphore.
 
 
 
|-
 
|TrySignal
 
<div style="font-style:italic; color:green;">Introduced 2005r1</div>
 
|
 
|[[Boolean|Boolean]]
 
|This is a more friendly version of the Signal method that gives you a sneak-peek to determine whether there is a lock available.
 
If there is a lock available, you are granted the lock and TrySignal returns [[True|True]]. When you are finished with the resource, call Release to give it back to the Semaphore. If the lock is not available, you do not wait for it. Instead, TrySignal returns [[False|False]] to let you know. Do not attempt to use the resource after it returns [[False|False]] because you are likely to collide with another thread. If you
 
 
 
|-
 
|}
 
 
 
 
 
==Constructors==
 
The '''Semaphore''' has a constructor that takes the initial count of the number of resources the semaphore is protecting as an optional parameter.
 
{| cellpadding="8" cellspacing="0" border="1"
 
 
 
! width=10%  style="background-color:#e0e0e0" | Name
 
 
 
! width=20%  style="background-color:#e0e0e0" | Parameters
 
 
 
! width=55%  style="background-color:#e0e0e0" | Description
 
|-
 
|Semaphore
 
 
 
|NumResources as [[Integer|Integer]]
 
|The number of resources the Semaphore is intended to protect. This defaults to 1.
 
If you need to manage access to a single resource, you can instead use a [[CriticalSection|CriticalSection]].
 
 
 
|-
 
|}
 
 
 
Every time you successfully obtain a lock on the resource, the '''Semaphore''' will decrement its internal count of available resources. When there are no more resources, threads that request locks will begin to block and wait for resources. This is why you are allowed to pass the initial count of resources, to give you more control over the behavior of the '''Semaphore'''.
 
 
 
The Semaphore class is different from the [[CriticalSection|CriticalSection]] and [[Mutex|Mutex]] classes in this way: calling Signal in the same thread will cause the counter to decrement. If you call Signal recursively, you will cause the application to hang.
 
 
 
 
 
 
 
=='''Notes'''==
 
 
A '''Semaphore''' is an object that can be used to coordinate access to a shared resource.
 
A '''Semaphore''' is an object that can be used to coordinate access to a shared resource.
  
To acquire the ownership of a semaphore, a thread calls the Signal or TrySignal methods. If the Semaphore isn't owned, the thread acquires ownership, otherwise the thread will be forced to wait until the Semaphore is released via the Release method by the owning thread.
+
To acquire the ownership of a semaphore, a thread calls the Signal or TrySignal methods. If the Semaphore isn't owned, the thread acquires ownership, which means you have a lock on it. Otherwise the thread is forced to wait until the Semaphore is released via the Release method by the owning thread.
 
 
 
 
 
 
=='''Examples'''==
 
The example uses a [[PushButton|Pushbutton]] in a window to spawn some threads. Its Action event code is:
 
{| cellpadding="8" cellspacing="0" border="1"
 
|<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// Make a new thread
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">[[Dim|Dim]] newThread as ThreadSpawn
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">newThread = [[New|New]] ThreadSpawn( [[Self|Self]], mNextID )
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// Be sure to advance our thread id
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">mNextID = mNextID + 1
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// And run the new thread
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">newThread.Run
 
<br /></div>
 
 
 
|-
 
|}
 
 
 
The ThreadSpawn class is derived from the [[Thread|Thread]] class. Its constructor takes a [[WindowClass|window]] and an integer as its parameters.
 
{| cellpadding="8" cellspacing="0" border="1"
 
|<div style="width:100%; background-color:#d0d0d0; padding-left:30px">[[Sub|Sub]] [[Constructor|Constructor]] (manager as Window1, ID as [[Integer|Integer]])
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;mSharedResourceManger = manager
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;mThreadNumber = ID
 
<br /></div>
 
 
 
|-
 
|}
 
 
 
mSharedResourceManager is a Window1 property of ThreadSpawn and mThreadNumber is an [[Integer|Integer]] property of ThreadSpawn.
 
  
Its Run event handler is:
+
Every time you successfully obtain an ownership lock on the resource, the '''Semaphore''' will decrement its internal count of available resources. When there are no more resources, threads that request ownership locks will begin to block and wait for resources. This is why you can specify the initial count of resources -- to give you more control over the behavior of the '''Semaphore'''.
{| cellpadding="8" cellspacing="0" border="1"
 
|<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// We're going to loop forever and ever
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">[[While|While]] [[True|True]]<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;// We want to try to access the shared
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;// resource, so we call it on the Window
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">mSharedResourceManager.ChangeSharedResource(mThreadNumber, [[Str|Str]]([[Rnd|Rnd]]) )
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">    
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;// And then go to sleep for some random amount of time
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">[[Me|Me]].Sleep([[Rnd|Rnd]] * 10000, [[True|True]] )
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">Wend
 
<br /></div>
 
  
|-
+
The Semaphore class is different from the [[CriticalSection]] and [[Mutex]] classes in this way: calling Signal in the same thread will cause the counter to decrement. If you call Signal recursively, you will cause the application to hang.
|}
 
  
When the window opens, the PushButton is pushed programmatically to create some threads. The window's Open event handler is:
+
== Sample Code ==
{| cellpadding="8" cellspacing="0" border="1"
+
This example uses a Semaphore to ensure that only one thread at a time writes to a file.
|<div style="width:100%; background-color:#d0d0d0; padding-left:30px">mLock = [[New|New]] '''Semaphore'''<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">  
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// We're going to spawn a few threads
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;&#xA0;// to start off with
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">[[For|For]] i as [[Integer|Integer]] = 0 to 4
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;PushButton1.Push
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">Next i
 
<br /></div>
 
  
|-
+
Add a public property to the App class:
|}
+
<rbcode>
 +
FileAccess As Semaphore
 +
</rbcode>
  
Window1 is derived from Window and has the ChangedSharedResource method:
+
And in the Open event handler, initialize it:
{| cellpadding="8" cellspacing="0" border="1"
+
<rbcode>
|<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// We want to make sure that only the right thread gets in here.  One at a  
+
// Allow only a single thread to access the file at a time
<br /></div>
+
FileAccess = New Semaphore(1)
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">// time!
+
</rbcode>
<br /></div>
 
<br />
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;&#xA0;//mLock is a '''Semaphore''' property of Window1
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;&#xA0;//mNextID is an [[Integer|Integer]] property of Window1
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">mLock.Signal
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">  
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;&#xA0;// Now that we're here, we can change the resource
 
<br /></div>
 
<br />
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;&#xA0;//SharedResource and AccessText are StaticTexts in Window1
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">SharedResource.Text = value
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">AccessText.Text = [[Str|Str]]( id )
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">  
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;// And now that we've done something with the
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">&#xA0;// resource, we want to release our lock on it
 
<br /></div>
 
<div style="width:100%; background-color:#d0d0d0; padding-left:30px">mLock.Release
 
<br /></div>
 
  
|-
+
In the thread, check the FileAccess semaphore to see if you can write to the file:
|}
+
<rbcode>
 +
// This will Suspend this thread if another has the lock
 +
// When it is released, this thread will continue to run
 +
App.FileAccess.Signal
  
 +
// Now you can open the file for writing
 +
WriteDataToFile // Call your code here
  
=='''See Also'''==
+
// When you are finished, release the semaphore
[[CriticalSection|CriticalSection]], [[Mutex|Mutex]], [[Thread|Thread]] classes.
+
App.FileAccess.Release
 +
</rbcode>
  
 +
==See Also==
 +
[[CriticalSection]], [[Mutex]], [[Thread]] classes.
  
[[Category:Multithreading]]
+
[[Category:Language_Classes]]
[[Category:Classes]]
+
[[Category:Language_Code_Execution]]
[[Category:Code_Execution]]
+
[[Category:Language_Multithreading]]

Latest revision as of 14:41, 1 October 2018

Class (inherits from Object)

Used to control access to resources in a multithreaded environment.

Methods
Release TrySignal
Signal


Constructors

Constructor(NumResources as Integer)


Notes

A Semaphore is an object that can be used to coordinate access to a shared resource.

To acquire the ownership of a semaphore, a thread calls the Signal or TrySignal methods. If the Semaphore isn't owned, the thread acquires ownership, which means you have a lock on it. Otherwise the thread is forced to wait until the Semaphore is released via the Release method by the owning thread.

Every time you successfully obtain an ownership lock on the resource, the Semaphore will decrement its internal count of available resources. When there are no more resources, threads that request ownership locks will begin to block and wait for resources. This is why you can specify the initial count of resources -- to give you more control over the behavior of the Semaphore.

The Semaphore class is different from the CriticalSection and Mutex classes in this way: calling Signal in the same thread will cause the counter to decrement. If you call Signal recursively, you will cause the application to hang.

Sample Code

This example uses a Semaphore to ensure that only one thread at a time writes to a file.

Add a public property to the App class:

FileAccess As Semaphore

And in the Open event handler, initialize it:

// Allow only a single thread to access the file at a time
FileAccess = New Semaphore(1)

In the thread, check the FileAccess semaphore to see if you can write to the file:

// This will Suspend this thread if another has the lock
// When it is released, this thread will continue to run
App.FileAccess.Signal

// Now you can open the file for writing
WriteDataToFile // Call your code here

// When you are finished, release the semaphore
App.FileAccess.Release

See Also

CriticalSection, Mutex, Thread classes.