Slim Read Write Locking

Windows specific forum
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Slim Read Write Locking

Post by RichAlgeni »

Been slammed recently, so I haven't been able to contribute as much as I would like. Lately I needed a way to serve data to multiple connections concurrently. I created a structured map. and used the Mutex library, but was concerned about the overhead involved using LockMutex when just reading the map. Then I found Slim Reader Writer Lock library:

https://msdn.microsoft.com/en-us/librar ... s.85).aspx

Code: Select all

EnableExplicit

Global *globalPointer  = AllocateMemory(SizeOf(Integer))
Global sharedInteger.i = 0

Define loopIndex.i

Import "D:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64\kernel32.lib"
    InitializeSRWLock(*globalPointer)
    TryAcquireSRWLockShared(*globalPointer)
    AcquireSRWLockShared(*globalPointer)
    ReleaseSRWLockShared(*globalPointer)
    TryAcquireSRWLockExclusive(*globalPointer)
    AcquireSRWLockExclusive(*globalPointer)
    ReleaseSRWLockExclusive(*globalPointer)
EndImport

InitializeSRWLock(*globalPointer)

OpenConsole()

Procedure incrementInteger(sessionNumber.i)
    Protected threadIndex.i
    For threadIndex=1 To 10000
        AcquireSRWLockExclusive(*globalPointer)
        sharedInteger + 1
        PrintN("Session = " + Str(sessionNumber) + ", sharedInteger = " + Str(sharedInteger))
        ReleaseSRWLockExclusive(*globalPointer)
        Delay(10)
    Next
   PrintN("Session = " + Str(sessionNumber) + " complete")
EndProcedure

For loopIndex=0 To 9
    CreateThread(@incrementInteger(), loopIndex)
Next

Delay(10000)

PrintN("Should be done now.")

Input()

CloseConsole()
; IDE Options = PureBasic 5.24 LTS (Windows - x64)
; ExecutableFormat = Console
; CursorPosition = 28
; EnableThread
; Executable = slim_read_write_lock01.exe
; DisableDebugger
; CurrentDirectory = D:\dev\PureBasic\testing\
; CompileSourceDirectory
The above code demonstrates that the threads to not collide when using the AcquireSRWLockExclusive() command, and writing to the console. When just reading data, you would use the AcquireSRWLockShared() command.

It was strange, but I could not get TryAcquireSRWLockExclusive to run without it bombing out with an error. Maybe someone else can figure it out.

kernel32.lib can be downloaded with the Microsoft SDK, or I can upload to my website, if needed.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Slim Reader Writer Locking

Post by RichAlgeni »

Here is the code with the Try that doesn't work

Code: Select all

EnableExplicit

Global *globalPointer  = AllocateMemory(SizeOf(Integer))
Global sharedInteger.i = 0

Define loopIndex.i

Import "D:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64\kernel32.lib"
    InitializeSRWLock(*globalPointer)
    TryAcquireSRWLockShared(*globalPointer)
    AcquireSRWLockShared(*globalPointer)
    ReleaseSRWLockShared(*globalPointer)
    TryAcquireSRWLockExclusive(*globalPointer)
    AcquireSRWLockExclusive(*globalPointer)
    ReleaseSRWLockExclusive(*globalPointer)
EndImport

InitializeSRWLock(*globalPointer)

OpenConsole()

Procedure incrementInteger(sessionNumber.i)
    Protected threadIndex.i
    Protected lockedOk.i

    For threadIndex=1 To 10000
        Repeat
            lockedOk = TryAcquireSRWLockExclusive(*globalPointer)
            If lockedOk > 0
                sharedInteger + 1
                PrintN("Session = " + Str(sessionNumber) + ", sharedInteger = " + Str(sharedInteger))
                ReleaseSRWLockExclusive(*globalPointer)
                Break
            Else
                Delay(10)
            EndIf
         ForEver
        Delay(10)
    Next
   PrintN("Session = " + Str(sessionNumber) + " complete")
EndProcedure

For loopIndex=0 To 9
    CreateThread(@incrementInteger(), loopIndex)
Next

Delay(10000)

PrintN("Should be done now.")

Input()

CloseConsole()
; IDE Options = PureBasic 5.24 LTS (Windows - x64)
; ExecutableFormat = Console
; CursorPosition = 28
; EnableThread
; Executable = slim_read_write_lock02.exe
; DisableDebugger
; CurrentDirectory = D:\dev\PureBasic\testing\
; CompileSourceDirectory
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Slim Read Write Locking

Post by RichAlgeni »

Think I figured it out. Microsoft says the return is type Boolean. So I changed the type from '.i' to '.a'. That seemed to fix TryAcquireSRWLockExclusive.

Code: Select all

EnableExplicit

Global *globalPointer  = AllocateMemory(SizeOf(Integer))
Global sharedInteger.i = 0

Define loopIndex.i

Import "D:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64\kernel32.lib"
    InitializeSRWLock(*globalPointer)
    TryAcquireSRWLockShared(*globalPointer)
    AcquireSRWLockShared(*globalPointer)
    ReleaseSRWLockShared(*globalPointer)
    TryAcquireSRWLockExclusive(*globalPointer)
    AcquireSRWLockExclusive(*globalPointer)
    ReleaseSRWLockExclusive(*globalPointer)
EndImport

InitializeSRWLock(*globalPointer)

OpenConsole()

Procedure incrementInteger(sessionNumber.i)
    Protected threadIndex.i
    Protected lockedOk.a

    For threadIndex=1 To 10000
        Repeat
            lockedOk = TryAcquireSRWLockExclusive(*globalPointer)
            If lockedOk > 0
                sharedInteger + 1
                PrintN("Session = " + Str(sessionNumber) + ", sharedInteger = " + Str(sharedInteger))
                ReleaseSRWLockExclusive(*globalPointer)
                Break
            Else
                Delay(10)
            EndIf
         ForEver
        Delay(10)
    Next
   PrintN("Session = " + Str(sessionNumber) + " complete")
EndProcedure

For loopIndex=0 To 9
    CreateThread(@incrementInteger(), loopIndex)
Next

Delay(10000)

PrintN("Should be done now.")

Input()

CloseConsole()
Note that when using the TryAquire method with a Delay of 10 seems to be much slower than just using the Acquire method. But, I would have to think that resource usage would also decrease. Thoughts anyone?
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Slim Read Write Locking

Post by RichAlgeni »

From Microsoft:

Slim reader/writer (SRW) locks enable the threads of a single process to access shared resources; they are optimized for speed and occupy very little memory.
Reader threads read data from a shared resource whereas writer threads write data to a shared resource. When multiple threads are reading and writing using a shared resource, exclusive locks such as a critical section or mutex can become a bottleneck if the reader threads run continuously but write operations are rare.

SRW locks provide two modes in which threads can access a shared resource:
Shared mode, which grants shared read-only access to multiple reader threads, which enables them to read data from the shared resource concurrently. If read operations exceed write operations, this concurrency increases performance and throughput compared to critical sections.

Exclusive mode, which grants read/write access to one writer thread at a time. When the lock has been acquired in exclusive mode, no other thread can access the shared resource until the writer releases the lock.

A single SRW lock can be acquired in either mode; reader threads can acquire it in shared mode whereas writer threads can acquire it in exclusive mode. There is no guarantee about the order in which threads that request ownership will be granted ownership; SRW locks are neither fair nor FIFO.

An SRW lock is the size of a pointer. The advantage is that it is fast to update the lock state. The disadvantage is that very little state information can be stored, so SRW locks cannot be acquired recursively. In addition, a thread that owns an SRW lock in shared mode cannot upgrade its ownership of the lock to exclusive mode.
Post Reply