Threading questions/problems

New to FreeBASIC? Post your questions here.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Threading questions

Post by fxm »

@Provoni
This topic may interest you:
Multithread Parameter Passing
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions

Post by Provoni »

Thanks all :)

vdecampo, what is PUSH/POP the stack? Yes, your version is more than twice as fast, I guess, mainly because you moved two subs into one? And what do you mean by large overhead?

Thanks fxm for your example, I'm still thinking if I will use ptr's or shared variable's. I need to do some testing if it really is such a big slow down. Also thanks for the topic link, I will go through it when I find some more time.

Thanks for clearing that up SARG, really good to know that I don't have to mutex array access if I don't access the same elements. That's why my program worked fine but the counter was off.
SARG
Posts: 1756
Joined: May 27, 2005 7:15
Location: FRANCE

Re: Threading questions

Post by SARG »

Provoni wrote:vdecampo, what is PUSH/POP the stack? Yes, your version is more than twice as fast, I guess, mainly because you moved two subs into one? And what do you mean by large overhead?
When a sub or a function is called, parameters and return adress are stored (push) on the stack and at the end of the call they are removed (pop).
This process consumes processor time so if it's possible to avoid them the program runs faster.
Here the overhead is that "unnecessary" time added to your code (search of prime).
Provoni wrote: Thanks for clearing that up SARG, really good to know that I don't have to mutex array access if I don't access the same elements. That's why my program worked fine but the counter was off.
No problem you are welcome.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Threading questions

Post by MichaelW »

Provoni wrote:Is it possible to end one of these threads without user made flags?
By “user made flags” I’m assuming that you mean a shared variable used to direct the thread procedure to return, ending the thread. FWIW under Windows you can use TerminateThread to force a thread to exit, but note in the Remarks section the potentially adverse effects of doing so. I tested the code below under Windows XP SP3, compiled with 0.90.1, -gen gas and -gen gcc.

Code: Select all

#include "windows.bi"

sub Thread( userdata as any ptr )
    do
        print ".";
        sleep 100
    loop
end sub

dim as any ptr fbThread = threadcreate( @Thread )

dim as HANDLE hThread = *cast(HANDLE ptr,fbThread)

sleep

''----------------------------------------------
'' The Windows TerminateThread function returns
'' non-zero for success or zero for failure.
''----------------------------------------------

print TerminateThread( hThread, 0 )

sleep

/'
From the FreeBASIC 0.90.1 source \rtlib\fb_private_thread.h:

struct _FBTHREAD {
#if defined HOST_DOS
	int id;
#elif defined HOST_UNIX
	pthread_t id;
#elif defined HOST_WIN32
	HANDLE id;
#elif defined HOST_XBOX
	HANDLE id;
#else
#error Unexpected target
#endif
	FB_THREADPROC proc;
	void         *param;
	void         *opaque;
};

From FreeBASIC 0.90.1 source \rtlib\win32\thread_core.c:

FBCALL FBTHREAD *fb_ThreadCreate( FB_THREADPROC proc, void *param, int stack_size )
{
	FBTHREAD *thread = (FBTHREAD *)malloc( sizeof(FBTHREAD) );
	if( thread == NULL )
		return NULL;

	thread->proc = proc;
	thread->param = param;

#ifdef HOST_MINGW
	/* Note: _beginthreadex()'s last parameter cannot be NULL,
	   or else the function fails on Windows 9x */
	unsigned int thrdaddr;
	thread->id = (HANDLE)_beginthreadex( NULL, stack_size, threadproc, (void *)thread, 0, &thrdaddr );
#else
	DWORD dwThreadId;
	thread->id = CreateThread( NULL, stack_size, threadproc, (void*)thread, 0, &dwThreadId );
#endif

	if( thread->id == NULL ) {
		free( thread );
		thread = NULL;
	}

	return thread;
}
'/
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions

Post by Provoni »

Thanks MichaelW.

I've run into some problems with the threading in one of my programs. I'm trying to thread a sub which is responsible for drawing stuff on the screen with line and draw string. I made sure to put all shared variables inside a mutex.

Screenlock and unlock seem not to work as intended with 2 threads or more.

Also my program kept locking up until I remarked this line: if x1<dxbound1 and y1<dybound1 and x1>dxbound2 and y1>dybound2 then. None of these variables are shared, they are local to the sub.

I still get lockups on start, showing a white screen. If it doesn't lockup on the first batch of threadcalls it doesn't crash anymore for as long as I run it.

Thanks
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions/problems

Post by Provoni »

This code shows the problem. Some threads just ignore screenlock, as well as random lockups.

Code: Select all

declare sub MYTHREAD(byval hey as any ptr)
 
dim shared as integer threads=4 'number of threads
dim shared as byte inc
dim as any ptr thread(threads)
dim as longint i,j
 
screenres 600,600,32
color rgb(200,200,200)

for i=1 to 10000
    screenlock
    cls
    for j=1 to threads 'create threads
        thread(j)=threadcreate(@MYTHREAD,@inc)
    next j
    for j=1 to threads 'wait for threads to end
        threadwait(thread(j))
    next
    inc=0
    screenunlock
next i

beep
sleep

sub MYTHREAD(byval hey as any ptr)
    dim as any ptr mylock=mutexcreate()
    mutexlock mylock
    inc=inc+1
    dim as byte i=inc
    mutexunlock mylock
    select case i
    case 1
        line(0,0)-(600,150),,bf
    case 2
        line(0,150)-(600,300),,bf
    case 3
        line(0,300)-(600,450),,bf
    case 4
        line(0,450)-(600,600),,bf
    end select
end sub
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Threading questions/problems

Post by dkl »

The FB graphics library is not yet thread safe, unfortunately. That means it cannot safely be used used from multiple threads at the same time. It's supposed to be fixed someday, but it's not easy.
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions/problems

Post by Provoni »

Hey dkl, thanks for letting me know.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Threading questions/problems

Post by fxm »

Another remark:
- Your mutex structure is inefficient because each thread works with its own local mutex!
- You must define a shared mutex at the main body level before start the threads execution:
dim shared as any ptr mylock
mylock=mutexcreate()
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Threading questions/problems

Post by fxm »

Provoni wrote:This code shows the problem. Some threads just ignore screenlock, as well as random lockups.
Yes, fbgfx is not thread safe, and this may induce hangs, but when this runs, [ScreenLock...ScreenUnlock] seems to be well taken into account versus the drawing from the threads!

Test this program (yours slightly modified) without and with [ScreenLock...ScreenUnlock]:

Code: Select all

declare sub MYTHREAD(byval hey as any ptr)
 
dim shared as integer threads=4 'number of threads
dim shared as byte inc
dim as any ptr thread(threads)
dim as longint j
 
screenres 600,600,32
color rgb(200,200,200)

dim shared as any ptr mylock
mylock=mutexcreate()
do
'    screenlock
    cls
    sleep 100
    for j=1 to threads 'create threads
        thread(j)=threadcreate(@MYTHREAD,@inc)
    next j
    for j=1 to threads 'wait for threads to end
        threadwait(thread(j))
    next
    inc=0
    sleep 25
'    screenunlock
loop while inkey = ""

beep
sleep

sub MYTHREAD(byval hey as any ptr)
    mutexlock mylock
    inc=inc+1
    dim as byte i=inc
    mutexunlock mylock
    select case i
    case 1
        line(0,300)-(600,300)
    case 2
        line(0,0)-(600,600)
    case 3
        line(300,0)-(300,600)
    case 4
        line(600,0)-(0,600)
    end select
end sub
Flickers without [ScreenLock...ScreenUnlock] and no flickering with [ScreenLock...ScreenUnlock]!
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions/problems

Post by Provoni »

Hey fxm,

Thanks for your remarks, I made the mutex global now.

I experimented with your using of sleep in my program, it works fine until my program draws slower - due to heavy workload - than the sleep induced framerate.

I'm going to work around the problem for now, I'll start by moving all possible calculations outside of the drawing routine. Which will increase memory usage just a bit but that's okay. And then I'll start threading my calculation sub routine's.
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions/problems

Post by Provoni »

Hey all,

Another question,

I have a shared array(x,y) to which I need full access in every thread. Is it possible to create a copy, or an exclusive temporary of that array for each thread? Or will I have to add another dimension, array(threads,x,y)? Or do I need to use pointers to achieve this?

Thanks
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Threading questions/problems

Post by D.J.Peters »

The key is to control the array accesses via mutex.
http://www.freebasic.net/wiki/wikka.php ... gThreading

Joshy
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Threading questions/problems

Post by fxm »

We can group in a TYPE the thread code and all the necessary data to the threads for working:
- the thread procedure declared as static member procedure,
- the shared data declared as static member data,
- the specific data declared as non-static member data,
and pass at each thread its dedicated instance pointer.

See my previous example modified as following:

Code: Select all

'----- thread type definition -----
 
type thread
  dim as any ptr pthread
  dim as integer colour
  static as byte inc
  static as any ptr mylock
  declare static sub mythread (byval hey as any ptr)
end type

dim as byte thread.inc

dim as any ptr thread.mylock

static sub thread.mythread (byval p as any ptr)
  dim as thread ptr pt = p
  with *pt
    mutexlock .mylock
    .inc =. inc + 1
    sleep 1
    dim as byte i = .inc
    mutexunlock .mylock
    select case i
    case 1
      line(0,300)-(600,300), .colour
    case 2
      line(0,0)-(600,600), .colour
    case 3
      line(300,0)-(300,600), .colour
    case 4
      line(600,0)-(0,600), .colour
    end select
  end with
end sub

'----- Main program -----
 
screenres 600, 600, 8

dim as thread threads(0 To 3)

thread.mylock = mutexcreate()
do
  screenlock
  cls
  sleep 100
  for i as integer = lbound(threads) to ubound(threads) 'create threads
    threads(i).colour = 11 + i
    threads(i).pthread = threadcreate(@thread.mythread, @threads(i))
  next i
  for i as integer = lbound(threads) to ubound(threads) 'wait for threads to end
    threadwait(threads(i).pthread)
  next
  thread.inc = 0
  sleep 25
  screenunlock
loop while inkey = ""
mutexdestroy thread.mylock

sleep
Remark: 'sleep 1' in the [mutexlock..mutexunlock] block is put just to highlight the importance of a mutex when the threads use a shared variable with a read/write access (put in comment the two lines 'mutexlock .mylock' and 'mutexunlock .mylock' and see the result!).
Provoni
Posts: 513
Joined: Jan 05, 2014 12:33
Location: Belgium

Re: Threading questions/problems

Post by Provoni »

D.J.Peters and fxm, you'll have to excuse me because I asked a stupid question. Somehow I didn't pop up in my mind that I could just create a local version of my array in each thread.

I have some questions about your example fxm,

First of all, thanks for making me aware of with-end with, I can really put that to good use.

I don't understand the concept of static variables, you also made the sub static? This is very new for me and the FBWiki has allot to say about the subject. I'm not sure if I really need to use this. I also noticed you declared a sub in a UDT?
Post Reply