Simulated semaphores & mutexes [ in Blitz3D ]

Blitz3D Forums/Blitz3D Programming/Simulated semaphores & mutexes [ in Blitz3D ]

virtlands(Posted 2013) [#1]
Hi,
this post is dedicated to simulating mutexes (and semaphores),
without the need to actually use real mutexes and semaphores.

I invented (as follows) a simple demo that duplicates the behavior of a mutex.

All that is required for this code is the FastPointer package.
http://uploadingit.com/file/gl08cmr3gytfbjia/FastPoiner%20%26%20FreeImage%20DLLs.zip

Links to sample program, ( version 'a' )

-- http://uploadingit.com/file/6iqupameqpjk0dzq/SimulatedSemaphore_a.zip
-- https://www.dropbox.com/s/wq6ihxsz8xkdwwg/SimulatedSemaphore_a.zip


A mutex or semaphore is a software method to control access by multiple threads to common resources,
data and commands while running multiple threads.
( Wikipedia: http://en.wikipedia.org/wiki/Semaphore_%28programming%29 )



In my demo program, 12 threads enter the "SampleF(v)" function nearly simultaneously.
They are then all paused near the start of the that function.
Then soon, a trigger function called "Find_Resume_Th(n)"
gives each thread an invitation to quickly resume, in an
organized fashion, so that only 1 thread passes over the function
at a time. This, basically duplicates the behavior of a mutex.

When Slip>1 the code behaves like a semaphore instead of a mutex.
-----------------------------------------------------------------
Some interesting stuff I discovered about threads [in Blitz3D]:

(a) A thread can pause itself and other threads, using PauseThread(t)
(b) A thread can delete itself and other threads, using FreeThread(t)

(c) A paused thread cannot self-resume, but an active thread may resume another thread.

(d) Threads can not create other threads.
(e) Threads will normally STOP at the end of their thread function, and cease to exist as threads.

(f) Threads can escape into the main program by using the "GotoPointer #####" function.

(g) Threads will stop and stay stuck at a Waitkey(). The main program will not pause to take that input.
( --That situation will basically ruin your program.)

(h) Threads can not apparently do any graphics, (but maybe they can with special assistance from the main program).

(i) Threads that use "Print" statements will trim away leading whitespaces.
---------------------


virtlands(Posted 2013) [#2]
Plan A:
Later, I shall work on some code that will allow the main program to read/write/share data resources with threads.

The goal is to do that without errors (and conflicts).

For example, the following are obvious problems to think about: (All are assumed to be simultaneous actions.)

(a) It's okay to allow two or more threads to read a variable simultaneously.
(b) Avoid reading a variable while another thread writes to that variable.
(c) Avoid writing to a variable while another thread reads that variable.
(c) Avoid having two or more threads write to the same variable at the same time.

(d) Typically, one thread does not know what another thread is doing, unless you find a way to synchronize them.

To be continued...


virtlands(Posted 2013) [#3]
Okay, this was exhausting...

This is version 'c'. It may be an improvement over version 'a', but I'm not sure.





The way this example works is like this:

The goal is to let 7 threads contribute 1 letter at a time to a global
alphabet (alph$) variable, and each thread must politely take its turn when doing so.

(You can choose any number of threads you wish, I just chose 7 as an example.)

7 threads enter function SampleF(v), (nearly simultaneously).
All 7 threads work their way through a Repeat-Forever block, and they
are stuck in that Repeat-Forever block until all 26 letters are achieved.

Threads that (in the interim) are not "chosen" to add a letter may
optionally be paused, or their efforts may be sent elsewhere (in future code).

Additionally, the "main program" thread here is called Thread 0 (zero).
In this example, thread 0's only responsibility is to wait
in a loop and see when it is chosen to make a decision.
When Thread 0 is chosen, all it does it hand responsibility back to Thread 1,
...but in a potentially more advanced program, Thread 0 could actually
be doing something useful, like drawing pixels, or working on other stuff.

Notes::

(A). Thread 0 (main program) may read the value of global th_allow,
but it may not write to that variable. That would cause chaos.

(B). The currently "chosen" thread may freely change the value of th_allow to any other thread it wishes,
since no other thread currently has permission to write to th_allow .
In other words, it passes the torch to someone else.

Hope that it all makes sense. It's just an experiment.


Yasha(Posted 2013) [#4]
I... am genuinely baffled by this example.

Firstly, what does it demonstrate about threading? This task is inherently non-parallel; all you're doing is pausing threads so that others can have a go doing something, which ... defeats the entire purpose of having threads at all. How does this example stretch to actually parallelising work and allowing concurrent access to data?

Secondly, no part of this involves mutex. It is not possible, on any level, to simulate a mutex in software. They only work because of platform-specific CPU-instruction-level support.

I'm having difficulty following the logic of the example, and it could well be that your logic is safe for this particular example because the linear, non-threaded nature of the task means there might never be a conflict here, but I must reiterate that there is absolutely no way to implement a generally-reliable mutex in software. It cannot be done by definition. Writing to globals is not atomic: when two threads are working on the same task at the same time there is no way for them to safely write to one global variable. That's... the entire point of why this is an issue. I think this example only works because you've set the threads up so that they don't work concurrently.

I don't mean to sound pessimistic or to dismiss the thought you've put into this, but it's really not a problem that can be usefully solved by global variables.

(On a more theoretical and annoying level, I would continue to argue that mutexes and semaphores do not constitute multithreading support anyway: they're what you use to build support into a higher-level language that hides them completely from the user, but they themselves are also very difficult to use properly.)


virtlands(Posted 2013) [#5]
Well, maybe the BTS instruction comes close to mutex use,
and only as you said for "platform-specific CPU-instruction-level support".

BTS = Bit Test and Set, part of the x86 instruction set.
http://en.wikipedia.org/wiki/Bit_Test
---------------------------------------------------------------------
(On a more theoretical and annoying level, I would continue to argue that mutexes and semaphores do not constitute multithreading support anyway: they're what you use to build support into a higher-level language that hides them completely from the user, but they themselves are also very difficult to use properly.)

Looks like that explains it.