Is there a thread-safe sleep command?

General FreeBASIC programming questions.
chrowle
Posts: 47
Joined: Oct 21, 2013 23:32
Location: Alberta, Canada

Is there a thread-safe sleep command?

Post by chrowle »

Hello, I am writing a game, but it is using 98% cpu. I tried using

Code: Select all

sleep 1, 1
to free up some memory, but then strange other glitches (such as the seperate music thread slowing down and acting strange, eg. music is distorted, etc.). I have so far tracked it down to the sleep command not being thread safe. Is there an equivalent that is thread safe?
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Is there a thread-safe sleep command?

Post by MichaelW »

Are you sure that the problem is not with the length of the wait? I don’t know about Linux, but under Windows a Sleep 1 will normally wait for no less than 10ms.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Is there a thread-safe sleep command?

Post by dodicat »

I regulate speed by sleeping for a bit.
This is quite cpu friendly.
Here's a small screen regulated to about 20 fps by adjusting the sleeptime each frame.
Not much cpu activity in the task manager.
(Just a thought).

Code: Select all

Function framecounter() As Integer
    Var t1=Timer,t2=t1
    Static As Double t3,frames,answer
    frames+=1
    If (t2-t3)>=1 Then t3=t2:answer=frames:frames=0
    Function= answer
End Function
Function Regulate(MyFps As Integer,Byref fps As Integer) As Integer
    fps=framecounter()
    Static As Double timervalue,lastsleeptime
    Dim As Double delta
    Var k=fps-myfps,i=1/myfps
    If Abs(k)>1 Then delta+=i*Sgn(k)
    Var sleeptime=lastsleeptime+(i-Timer+timervalue)*2000+delta
    If sleeptime<1 Then sleeptime=1
    lastsleeptime=sleeptime
    timervalue=Timer
    Return sleeptime
End Function

screen 7
color ,4
dim as integer fps
do
    var sleeptime= regulate(20,fps)
    screenlock
    cls
    draw string (50,50),"FPS = " &fps
    draw string(50,70),"SLEEP " &sleeptime 
    screenunlock
    sleep sleeptime
    loop until len(inkey) 
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Is there a thread-safe sleep command?

Post by marcov »

Or that "hidden" music thread somehow is entangled with the main thread(via a lock/critical section)?
Landeel
Posts: 777
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Is there a thread-safe sleep command?

Post by Landeel »

Are you using SCREENSYNC in your main/rendering thread?
chrowle
Posts: 47
Joined: Oct 21, 2013 23:32
Location: Alberta, Canada

Re: Is there a thread-safe sleep command?

Post by chrowle »

@Landeel No, don't think I've heard of SCREENSYNC. I'll try it though.
chrowle
Posts: 47
Joined: Oct 21, 2013 23:32
Location: Alberta, Canada

Re: Is there a thread-safe sleep command?

Post by chrowle »

@marcov This is the music thread:

Code: Select all

Sub musicplaying() 'Play the music in the background, in a separate thread
        Do
          	PLAY music
        Loop
End Sub
EDIT: Also, I am using Fedora 19 (so, Linux.)
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Is there a thread-safe sleep command?

Post by D.J.Peters »

chrowle wrote:

Code: Select all

Sub musicplaying() 'Play the music in the background, in a separate thread
        Do
          	PLAY music
        Loop
End Sub
the DO LOOP without any condition to abort around the play command looks strange for me.

Normaly a FreeBASIC thread proc looks like this.

Code: Select all

Sub musicplaying_thread(parg as any ptr)
    PLAY music
End Sub

ThreadCreate @musicplaying_thread,0
or

Code: Select all

Sub musicplaying
    PLAY music ' starts a seperate thread
End Sub

musicplaying
chrowle
Posts: 47
Joined: Oct 21, 2013 23:32
Location: Alberta, Canada

Re: Is there a thread-safe sleep command?

Post by chrowle »

I am using ThreadCall, so my thread creation looks like this:

Code: Select all

Sub musicplaying() 'Play the music in the background, in a separate thread
        Do
          	PLAY music
        Loop
End Sub

Dim as any ptr musicthread = threadcall musicplaying 'the music thread
xbgtc
Posts: 249
Joined: Oct 14, 2007 5:40
Location: Australia

Re: Is there a thread-safe sleep command?

Post by xbgtc »

Yes sleep_
ie. sleep_ 100

but that 98% cpu usage would be from that music thread. Use joshy's idea ;)
pestery
Posts: 493
Joined: Jun 16, 2007 2:00
Location: Australia

Re: Is there a thread-safe sleep command?

Post by pestery »

I'm a little late to the party, but I have a semi related question. I just checked the source code and the FreeBASIC Sleep() command calls a function called fb_Delay(). The Unix version of fb_Delay() calls the network command Select(), which is what does the work.

So in short, on Unix/Linux, Sleep() is for the most part just an alias for Select(). I'm a Windows user and have not idea about the Unix/Linux API but isn't there another function that could be used instead? Sorry if I'm coming of critical, it's just that from my understanding Select() is not intended to be used at a sleep command.
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Re: Is there a thread-safe sleep command?

Post by anonymous1337 »

pestery wrote:I'm a little late to the party, but I have a semi related question. I just checked the source code and the FreeBASIC Sleep() command calls a function called fb_Delay(). The Unix version of fb_Delay() calls the network command Select(), which is what does the work.

So in short, on Unix/Linux, Sleep() is for the most part just an alias for Select(). I'm a Windows user and have not idea about the Unix/Linux API but isn't there another function that could be used instead? Sorry if I'm coming of critical, it's just that from my understanding Select() is not intended to be used at a sleep command.
I have investigated the use of select() on Unix-type systems, and I am hearing through the grapevine that it is used because it will not interfere with other timing mechanisms. It has high resolution (4ms or so), and is apparently completely valid when called the way fb is doing:

https://github.com/freebasic/fbc/blob/m ... ys_delay.c

Code: Select all

#include "../fb.h"
#include <sys/select.h>

FBCALL void fb_Delay( int msecs )
{
	struct timeval tv;
	tv.tv_sec = msecs / 1000;
	tv.tv_usec = (msecs % 1000) * 1000;
	select(0, NULL, NULL, NULL, &tv);
}
An explicit change to use select() instead of usleep() was made 9 years ago by lillo!
https://github.com/freebasic/fbc/commit ... 3abfc3040f

(Thanks dkl for the find.)

As for Windows, if you call sleep using Sleep n, 1:

http://sourceforge.net/p/fbc/code/ci/ma ... _sleepex.c

Code: Select all

/* sleep multiplexer function */

#include "fb.h"

/*:::::*/
FBCALL int fb_SleepEx ( int msecs, int kind )
{
    switch( kind ) {
    case 0:
        fb_Sleep( msecs );
        break;
    case 1:
        fb_Delay( msecs );
        break;
    default:
        return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
    }
    return fb_ErrorSetNum( FB_RTERROR_OK );
}
fb_Delay is then called, which is defined using the Windows Sleep command in the win32 section of the rtlib.

http://sourceforge.net/p/fbc/code/ci/ma ... ys_delay.c

Code: Select all

#include "../fb.h"
#include <windows.h>

FBCALL void fb_Delay( int msecs )
{
	Sleep( msecs );
}
We can verify that fb_SleepEx@8 is called by looking at the output ASM. (Compile with fbc -r whatever.bas)

Furthermore, when you call Sleep n, fb_Sleep@4 is called in the output ASM. The source for that is:

http://sourceforge.net/p/fbc/code/ci/ma ... leep.c#l10

Code: Select all

/* sleep function */

#include "fb.h"

/*:::::*/
FBCALL void fb_Sleep ( int msecs )
{
    FB_SLEEPPROC sleepproc;
    FB_LOCK();
    sleepproc = __fb_ctx.hooks.sleepproc;
    FB_UNLOCK();
    if( sleepproc ) {
        sleepproc( msecs );
    } else {
        fb_ConsoleSleep( msecs );
    }
}
if sleepproc isn't set (ex: we're in a console), fb_Sleep defaults to the fb_ConsoleSleep, which has the following source:

http://sourceforge.net/p/fbc/code/ci/ma ... me_sleep.c

Code: Select all

/* sleep() function */

#include "fb.h"

void fb_ConsoleSleep( int msecs )
{
#if defined( HOST_XBOX )
    /* NOTE: No need to test for input keys because sleep will be hooked
     *       when the application is switched to graphics mode and the
     *       console implementations for keyboard handling are only dummy
     *       functions.
     */
	fb_Delay( msecs );
#else
	/* infinite? wait until any key is pressed */
	if( msecs == -1 ) {
		while( !fb_hConsoleInputBufferChanged( ) )
			fb_Delay( 50 );
		return;
	}

	/* if above n-mili-seconds, check for key input, otherwise,
	   don't screw the precision with slow console checks */
	if( msecs >= 100 ) {
		while( msecs > 50 ) {
			if( fb_hConsoleInputBufferChanged( ) )
				return;

			fb_Delay( 50 );
			msecs -= 50;
		}
	}

	if( msecs >= 0 )
		fb_Delay( msecs );
#endif
}
But if a graphics window is set, fb_Sleep will perform the following on Windows:

http://sourceforge.net/p/fbc/code/ci/ma ... fx_sleep.c

Code: Select all

/* sleep function */

#include "fb_gfx.h"

int fb_hGfxInputBufferChanged( void );

/*:::::*/
void fb_GfxSleep ( int msecs )
{
	/* infinite? wait until any key is pressed */
	if( msecs == -1 )
	{
		while( !fb_hGfxInputBufferChanged( ) )
			fb_Delay( 50 );
		return;
	}

	/* if above n-mili-seconds, check for key input, otherwise,
	   don't screw the precision with slow console checks */
	if( msecs >= 100 )
		while( msecs > 50 )
		{
			if( fb_hGfxInputBufferChanged( ) )
				return;

			fb_Delay( 50 );
			msecs -= 50;
		}

	if( msecs > 0 )
		fb_Delay( msecs );

}
So I think we are observing different things. (This applies to the Windows comments only.)
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Is there a thread-safe sleep command?

Post by dkl »

It was changed from usleep() to select() here:
now using select() instead of usleep(), much more precise

This gives some more ideas why it's useful:
http://stackoverflow.com/questions/3125 ... d-of-sleep
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Is there a thread-safe sleep command?

Post by marcov »

pestery wrote:Sorry if I'm coming of critical, it's just that from my understanding Select() is not intended to be used at a sleep command.
It used to be the typical maximally cross-*nix (though wrongly advocated as crossplatform) way, and is thus recommended in many textbooks.

Std 1003.1b-1993 introduced nanosleep, and since late nineties that mostly supplanted select() for timing.

Added after seeing dkl's response:

I browsed a bit and noticed two things:
1. people recommend select over nanosleep based on timer ticks, but those posts are from 2000 era, not 2.4/2.6 series
2. nanosleep is linked to scheduler granularity. ("ticks").
Post Reply