semaphore versus global
semaphore versus global
Hi,
Does using a global flag (set to zero and 1) and doing a repeat until flag=1 versus using a semaphore make a difference? In other words, would the semaphore waitsemaphore() be better than a: repeat until flag=1 where flag is global?
Does using a global flag (set to zero and 1) and doing a repeat until flag=1 versus using a semaphore make a difference? In other words, would the semaphore waitsemaphore() be better than a: repeat until flag=1 where flag is global?
Re: semaphore versus global
or rather::
repeat
Waitwindowevent()
<some click, create threads>
...now one cannot do a semaphore wait here as it would block the code/ a spin lock would be the same.....
so it would be easier to do a
if someglobal=true do what you want with thread output
else stick to waitwindowevent loop?
until event=closewindow
so what does the semaphore give you? because either the way the internal implementation cannot be different from a spin lock (NOP till semaphore=1 kinds)
repeat
Waitwindowevent()
<some click, create threads>
...now one cannot do a semaphore wait here as it would block the code/ a spin lock would be the same.....
so it would be easier to do a
if someglobal=true do what you want with thread output
else stick to waitwindowevent loop?
until event=closewindow
so what does the semaphore give you? because either the way the internal implementation cannot be different from a spin lock (NOP till semaphore=1 kinds)
Re: semaphore versus global
If I remember correctly
waitsemephore the OS suspends the thread and switches context, it won't consume any cpu at all until you signal it.
which will force the OS to do a context change and resume the thread.
Advantages you don't need to run a loop checking for a global state or require that you to use a delay other than for enabling the thread to give up its time slice gracefully eg delay(0) if the business in the thread is going to take longer than the thread time slice.
The issue with example code below is that it has potential to block the main loop if the thread routine takes longer to run than a user clicking the button. If you didn't want that to happen you'd need to marshal the data with a mutex protected fifo, so the worker thread would just keep pulling items off the fifo unitl it's emptied the queue and then go back to sleep.
waitsemephore the OS suspends the thread and switches context, it won't consume any cpu at all until you signal it.
which will force the OS to do a context change and resume the thread.
Advantages you don't need to run a loop checking for a global state or require that you to use a delay other than for enabling the thread to give up its time slice gracefully eg delay(0) if the business in the thread is going to take longer than the thread time slice.
The issue with example code below is that it has potential to block the main loop if the thread routine takes longer to run than a user clicking the button. If you didn't want that to happen you'd need to marshal the data with a mutex protected fifo, so the worker thread would just keep pulling items off the fifo unitl it's emptied the queue and then go back to sleep.
Code: Select all
Global gListSeme = CreateSemaphore()
Global glmut = CreateMutex()
Global grun,tidList,ct
#Gadget = 1
Procedure Test(run)
Protected i,n
grun = run
While grun
WaitSemaphore(gListSeme) ;thread waits here
If grun
Debug "signaled"
LockMutex(glmut) ;lock mutex here as action is across thread boundary
For i = 0 To CountGadgetItems(#Gadget)
Debug GetGadgetItemText(#gadget,i)
Next i
UnlockMutex(glmut);unlock mutex here
EndIf
Wend
EndProcedure
OpenWindow(0,0,0,200,200,"test")
ListViewGadget(#Gadget,0,0,200,180)
ButtonGadget(0,0,180,60,20,"add")
;monitor thread
tidlist = CreateThread (@test(),1)
Repeat
ev = WaitWindowEvent()
evg = EventGadget()
evt = EventType()
If ev = #PB_Event_Gadget
If evg = 0
LockMutex(glmut);lock mutex to protect as you don't want to eat any add event
AddGadgetItem(#gadget,-1,"Data " + Str(ct))
UnlockMutex(glmut) ;unlock mutex here
SignalSemaphore(gListSeme)
ct+1
EndIf
EndIf
Until ev = #PB_Event_CloseWindow
Windows 11, Manjaro, Raspberry Pi OS


Re: semaphore versus global
say I do not want the parent to "wait/lock".
Basically my code is a sort of brute force multithreaded board calculator (say like sudoku etc) where each thread tries something on it's own.
so it is more like
Parent...
......
....waitwindowevent()
if some event X
callthread()
.......
...parent goes on...
...if thread has reply show output else just keep going as parent...
.......
until closewindow
my front end/user interface is controlled by the main thread.
My question is more specific that even if I use trysemaphore or trylockmutex, that part of the code has to still go on as the parent does not sleep.
So in effect if I cannot halt the execution of the parent, does it make a difference if I use a global flag or is it still better to use the trysemaphore/trymutex?
Note I cannot let the parent sleep, it still has to take inputs from the user / the front end cannot "hang".
Basically my code is a sort of brute force multithreaded board calculator (say like sudoku etc) where each thread tries something on it's own.
so it is more like
Parent...
......
....waitwindowevent()
if some event X
callthread()
.......
...parent goes on...
...if thread has reply show output else just keep going as parent...
.......
until closewindow
my front end/user interface is controlled by the main thread.
My question is more specific that even if I use trysemaphore or trylockmutex, that part of the code has to still go on as the parent does not sleep.
So in effect if I cannot halt the execution of the parent, does it make a difference if I use a global flag or is it still better to use the trysemaphore/trymutex?
Note I cannot let the parent sleep, it still has to take inputs from the user / the front end cannot "hang".
Re: semaphore versus global
marshal the data with a mutex protected fifo, so the worker thread can keep pulling items off the fifo unitll it's emptied the queue and then go back to sleep. and let the thread output the data.
so all your event loop has to do is handle user events
so all your event loop has to do is handle user events
Code: Select all
Global gListSeme = CreateSemaphore()
Global glmut = CreateMutex()
Global NewList fifo.s()
Global grun,tidList,ct
#Gadget = 1
Procedure Test(run)
Protected result.s
grun = run
While grun
WaitSemaphore(gListSeme) ;thread waits here
If grun
Debug "signaled"
While ListSize(fifo()) > 0 ;possibly dangerous
LockMutex(glmut) ;lock mutex
FirstElement(fifo())
result = fifo()
DeleteElement(fifo())
UnlockMutex(glmut)
Delay(500) ;procees data
AddGadgetItem(#gadget,-1,result)
Wend
EndIf
Wend
EndProcedure
OpenWindow(0,0,0,200,200,"test")
ListViewGadget(#Gadget,0,0,200,180)
ButtonGadget(0,0,180,60,20,"add")
;monitor thread
tidlist = CreateThread (@test(),1)
Repeat
ev = WaitWindowEvent()
evg = EventGadget()
evt = EventType()
If ev = #PB_Event_Gadget
If evg = 0
LockMutex(glmut);lock mutex to protect as you don't want to eat any add event
LastElement(fifo())
AddElement(fifo())
fifo() = "Data " + Str(ct)
UnlockMutex(glmut)
SignalSemaphore(gListSeme)
ct+1
EndIf
EndIf
Until ev = #PB_Event_CloseWindow
Windows 11, Manjaro, Raspberry Pi OS


Re: semaphore versus global
buffer is a global , ring buffer kinds
so anyone can read or write to the buffer
there is a global routine for it.
Incase of ring buffers the idea is that anyone can read or write to the buffer as long as read pointer and write pointer do not overlap
so if readptr=writeptr , all data has been read
if writeptr=readptr-1 , end of buffer/cant write more data etc.
http://en.wikipedia.org/wiki/Circular_buffer
so anyone can read or write to the buffer
there is a global routine for it.
Incase of ring buffers the idea is that anyone can read or write to the buffer as long as read pointer and write pointer do not overlap
so if readptr=writeptr , all data has been read
if writeptr=readptr-1 , end of buffer/cant write more data etc.
http://en.wikipedia.org/wiki/Circular_buffer
Re: semaphore versus global
a Circular buffer would still need protecting with a mutex, they are useful when you know the number of items going into it or when you want to buffer x items before pulling an item off, if the head = tail you either have to pull an item off, overwrite an entry or reallocate it.
Using a List as a Fifo is probably better when the potential queue size is unbound.
Using a List as a Fifo is probably better when the potential queue size is unbound.
Windows 11, Manjaro, Raspberry Pi OS


Re: semaphore versus global
hmm but take this case
there is 1 "reader and 1 writer" per thread1-->thread 2 pair.
the reader thread has to check if readptr=writeptr else there is data to read, and the writer thread has to check if readtptr-1=writeptr else write..
in other words, like in case of microcontrollers of assembler levels, we allocated a stack for each thread to thread communication.
Else the single buffer will have to know how to send the relevant data to the relevant thread no?
(P2P thread circular queue)
simply check if readptr!=writeptr then read data, and writer checks, if writeptr!=readptr-1 (this is a circular buffer) the write data
Simpler to do, except each thread has to check all its incoming buffers periodically.
there is 1 "reader and 1 writer" per thread1-->thread 2 pair.
the reader thread has to check if readptr=writeptr else there is data to read, and the writer thread has to check if readtptr-1=writeptr else write..
in other words, like in case of microcontrollers of assembler levels, we allocated a stack for each thread to thread communication.
Else the single buffer will have to know how to send the relevant data to the relevant thread no?
(P2P thread circular queue)
simply check if readptr!=writeptr then read data, and writer checks, if writeptr!=readptr-1 (this is a circular buffer) the write data
Simpler to do, except each thread has to check all its incoming buffers periodically.
Re: semaphore versus global
generally you'd do a read and write as one operation in a ring buffer
every time you add something to the buffer beyond a given buffer threshold you try to remove something from it.
so you shouldn't need to perform any periodic checks at all.
every time you add something to the buffer beyond a given buffer threshold you try to remove something from it.
so you shouldn't need to perform any periodic checks at all.
Windows 11, Manjaro, Raspberry Pi OS


Re: semaphore versus global
I am not sure what you mean here but micros and board levels have no schedulers. It is always "each to his own".. remember back to back unix sockets? there is no "multicast socket" the writer has to write to all unicasts.