How to Manage a Critical Section of the code of a Thread in FB

Forum for discussion about the documentation project.
badidea
Posts: 2636
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by badidea »

I see it mostly as a warning: freebasic's variable length strings and multithreading don't work well together.

An example of a generated crossword for which I am now using multithreading as I ran out out ideas to speed up the code otherwise: https://github.com/verybadidea/crosswor ... -02-13.png
deltarho[1859]
Posts: 4699
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by deltarho[1859] »

badidea wrote:freebasic's variable length strings and multithreading don't work well together.
A comment worth remembering. :wink:
badidea
Posts: 2636
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by badidea »

Maybe to add: If speed gain is your goal.
fxm
Moderator
Posts: 12575
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by fxm »

and if at least two threads (including the main thread) use var-len strings.
deltarho[1859]
Posts: 4699
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by deltarho[1859] »

fxm wrote:and if at least two threads (including the main thread) use var-len strings.
That has set 'the cat amongst the pigeons' rendering 'fix-len strings' to never get a look in.
deltarho[1859]
Posts: 4699
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by deltarho[1859] »

@badidea

I had a look at your github link.

If you have time, try the following.

Download CryptoRndIISource.zip and unzip to get the bas file.

Now try the following.
--------------------
Declare Function settimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
settimer
#include "CryptoRndIISource.bas" ' Using your path
#undef Rnd
#define Rnd cryptos

<Your generated crossword source>
--------------------
In 32-bit mode your generated crossword binary will increase by 19KiB.

In theory, generated crossword should get a noticeable performance boost. Don't worry if it does not - without analysing your code, I cannot tell whether it will be noticeable or not.
deltarho[1859]
Posts: 4699
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by deltarho[1859] »

Apologies - there was a typo in the link. :(
badidea
Posts: 2636
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by badidea »

The performance of Rnd is irrelevant for my application. It would save microseconds on a minutes (of even hours) timescale.

@moderator: This seems to go off-topic.
Last edited by badidea on Feb 16, 2025 10:19, edited 1 time in total.
deltarho[1859]
Posts: 4699
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by deltarho[1859] »

OK.

If an application only makes a few RND requests then even the quality of randomness is not an issue either and the Mersenne Twister is more than adequate.
badidea
Posts: 2636
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by badidea »

@fxm, I tried to follow your thread pooling code, but it looks so complicated, so I made my own.

Code: Select all

#include "string.bi"

const C_GN = 10, C_RD = 12, C_YL = 14, C_WH = 15

const THR_STAT_BUSY = 0
const THR_STAT_IDLE = 1
const THR_STAT_FINISHED = 2

dim as string thrStatusStr(...) = {"Busy", "idle", "finished"}

type sub_thread_type
	dim as any ptr handle 'thread handle
	dim as integer status = THR_STAT_IDLE
	dim as integer runCount = 0
	declare sub lauch()
end type

sub sub_thread_type.lauch()
	while true
		select case status
		case THR_STAT_BUSY
			sleep 3000, 1 'hard work
			runCount += 1
			status = THR_STAT_IDLE
		case THR_STAT_IDLE
			sleep 10, 1 'wait for new task or finish command
		case THR_STAT_FINISHED
			exit while
		end select
	wend
end sub

const MAX_THREADS = 4 'is number of (sub)threads
dim as sub_thread_type subThread(MAX_THREADS - 1)

'prepare threads -> idle
print "Launching threads... "; 
dim as double t0 = timer
for i as integer = 0 to MAX_THREADS-1
	subThread(i).handle = threadCreate(cptr(any ptr, @sub_thread_type.lauch), @subThread(i))
	sleep 1,1
next
print "ok" 

dim as integer maxRuns = 5
dim as integer doneCount
do
	doneCount = 0
	locate 2,1
	for i as integer = 0 to ubound(subThread)

		select case subThread(i).status
		case THR_STAT_BUSY
			color C_WH, 0
			'do nothing (wait)
		case THR_STAT_IDLE
			color C_YL, 0
			if subThread(i).runCount < maxRuns then
				subThread(i).status = THR_STAT_BUSY 'restart work
			else
				subThread(i).status = THR_STAT_FINISHED
			end if
		case THR_STAT_FINISHED
			color C_GN, 0
			doneCount += 1
		case else
			color C_RD, 0 'not possible
		end select

		print "thread(" & i & "): " & thrStatusStr(subThread(i).status) & " - " & subThread(i).runCount
	next
	sleep 100
loop while doneCount < MAX_THREADS

print "Clean up threads... ";
'clean up all threads
for i as integer = 0 to ubound(subThread)
	threadWait(subThread(i).handle)
next
print "ok"

dim as double t1 = timer
print "End: " & format(t1 - t0, "#.000") & "s"

getkey()
end
In the example above, all 'work' is sleeping for 3 seconds. This is repeated 'maxRuns' times per thread.
For the actual planned use, the work is variable in time. Each time a thread is done and idle, it will be given a new task until no more tasks are available. Actually, the same task, but for different data. Then we wait for all threads to finish.
Does this make any sense or am I approaching this too simplistic?
fxm
Moderator
Posts: 12575
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to Manage a Critical Section of the code of a Thread in FB

Post by fxm »

Summary for my 'ThreadPooling' and 'ThreadDispatching' features (see https://www.freebasic.net/forum/viewtop ... 12#p279512):
  • 'TreadPooling' feature:
    - The interest of my 'TreadPooling' feature is to manage a buffer queue of 'n' arbitrary user procedures to be executed by '1' internal sub-thread without having to restart (recreate) a sub-thread for executing each user procedure (only '1' internal sub-tread created in total).
    - The user only inserts his procedures into a buffer queue, independently of the rate at which they will actually be executed by the internal sub-thread.
  • 'TreadDispatching' feature:
    - The interest of my 'TreadDispatching' feature (an extension of 'ThreadPooling' feature) is to manage a buffer queue of 'n' arbitrary user procedures to be executed by 'p' internal sub-threads without having to restart (recreate) a sub-thread (among the 'p') for executing each user procedure (only 'p' internal sub-threads created in total).
    - The user only inserts his procedures into a single buffer queue (common to all sub-threads), regardless of the rate at which and by whom they will actually be executed among the internal sub-threads.

In your version above, the user tasks to be executed and their number are hard-coded at the sub-thread level.

My version provides the user with an abstraction of everything that is sub-thread control commands with their real times:
- Only two main methods for each feature: 'PoolingSubmit()' / 'DispatchingSubmit()', and 'PoolingWait()' / 'DispatchingWait()'.
- Everything else is handled internally by each feature.
Post Reply