Jump to content


Photo

Gmthreads 2 [updated: 30 Dec 2009]


  • Please log in to reply
204 replies to this topic

#1 Snake_PL

Snake_PL

    GMC Member

  • New Member
  • 57 posts

Posted 04 August 2008 - 11:25 AM

Posted Image

Last update (30 dec 2009):

Features:
- GM8 support
- Added thread_wait function, with which you can wait for a specified thread until it'll finish executing the code
- Now you can check whether an error occured in a given thread
- Library has been rewritten to MASM
- Source released (on LGPL)

Compatibility issues:
- Some functions has been renamed (thread_priority, thread_affinity_mask, thread_ideal_processor, thread_num_of_processors)
- thread_last_error and thread_is_suspended functions has been removed.
- Now when creating a thread you must close its handle with thread_close function. This allows you to retrieve an error code after the thread terminates (thread_get_error).


FAQ style

What is it ?

GMThreads is a DLL library, which can execute given GML code in... threads ;D Actually, this is an "experiment" and it needs to be tested.

What "threads" are you talking about ? ;o

Hmm... I do not want to describe this so I will quote:

A THREAD in computer science is short for a thread of execution. Threads are a way for a program to fork (or split) itself into two or more simultaneously (or pseudo-simultaneously) running tasks. Threads and processes differ from one operating system to another but, in general, a thread is contained inside a process and different threads in the same process share some resources while different processes do not.
Read more...

In what these threads can be useful ?

Well, in threads code is executed all the time, even when the game window is minimized, moved, displays a message [show_message], room changes etc. Besides, with threads you can load resources etc. at runtime and main game window will not freeze (FPS may decrease, but this also depends on the priority of the thread)

So... how to use this ?

Maybe i'll list functions first:
thread_init( filename ) - Initializes GMThreads. Optionally, You can specify path to GMThreads DLL (default: GMThreads.dll).
thread_create( GMLCode, Suspended? ) - Creates a thread with task to execute given GML code. If second argument is set to 1 (true) then created thread will be suspended. Returns thread handle, which can be used by functions listed below.
thread_suspend( ThreadHandle ) - Suspends thread. Returns 0 if error occured, otherwise 1.
thread_resume( ThreadHandle ) - Resumes thread. Returns 0 if error occured, otherwise 1.
thread_set_priority( ThreadHandle, Priority ) - Changes given thread's priority. Returns 0 if error occured, otherwise 1.
Argument "priority" can be set to:


0 - Idle
1 - Low
2 - Below normal
3 - Normal (default)
4 - Above normal
5 - High
6 - Realtime

thread_get_priority( ThreadHandle ) - Returns thread's priority or -1 if error occured.
thread_get_error() - Returns error code of the specified thread. Error code is set after the thread terminates. Error codes:

-1 = Invalid handle specified
0 = No error occured
1 = Game maker error (not existing variables/objects, array index out of bounds etc) or other unexpected error.

thread_terminate( ThreadHandle ) - Forces termination of given thread. Returns 0 if error occured, otherwise 1. Warning: Threads terminated with this function are unable to free used resources, causing memory leaks.
thread_is_running( ThreadHandle ) - Checks whether thread is running.
thread_set_affinity( ThreadHandle, Mask ) - Sets affinity mask to specified thread.
More info can be found here:
http://msdn.microsof...247(VS.85).aspx
thread_set_processor( ThreadHandle, ProcessorNum ) - Sets preferred processor for specified thread.
More info can be found here:
http://msdn.microsof...253(VS.85).aspx
thread_get_cpucount() - Returns number of processors.
thread_wait( Thread Handle, Timeout ) - Waits until the specified thread will finish executing the code or specified timeout interval elapses. Timeout argument specifies time in miliseconds to wait until the thread terminates. If you pass -1 to the parameter the function will return only when the thread terminates.

Creating a thread:
New thread can be created with thread_create function. Returned value (thread's handle) should be stored in variable to control it with other functions.
my_thread = thread_create( "repeat (1000) global.variable += 1;", 1 ); // create thread (suspended)
if ( my_thread ) {
  thread_set_priority( my_thread, 2 ); // Change priority to "below normal"
  thread_resume( my_thread ); // resume thread
} else
  show_message( "Could not create a thread." );

That code will create a new thread with lower priority or show an message if function fails. ;p Simple, huh ?

In given GML code you can define variables ( local_variable = 0... ), but they cannot be accessed from other objects ( even that one, which call that function ), except global variables. After code execution thread will be terminated.

"Infinite" code execution in threads
That's simple too. ;D You can use the while loop. For example:
my_thread = thread_create( "
  while ( true ) {
	if ( something ) {
	  do_something();
	}
	variable += 0.1;
  }
", 0 );
But you must keep in mind that, the code is executed asynchronously to room_speed, so execution will cause more CPU usage. Sometimes you will need to delay loop with sleep() function:
my_thread = thread_create( "
  while ( true ) {
	if ( something ) {
	  do_something();
	}
	variable += 0.1;
	sleep( 1000 ); // wait second
  }
", 0 );

Terminating thread:
You can terminate a thread with thread_terminate function, but use it only if You really need to terminate a thread, because terminated with this function are unable to free used resources/memory, causing memory leaks. To terminate an thread safely, You must use statements:
my_thread = thread_create( "
  while (!global.terminated) { // execute until thread is about to terminate
	do_something();
	do_something();
	do_something();
	if ( global.terminated ) exit; // terminate on this line when thread is about to terminate
	do_something();
	do_something();
  }
", 0 );
and all You must to do is set global.terminated variable to true ;o

Note:
Thread is running even when room changes, so You have to check for existance of objects or variables. When error occurs in GML code (syntax error, unknown variable or object etc.) - thread will be terminated without showing any error messages. You can also use an comments in code ;D


Known bugs:
- In threads, messages such as "show_message" cannot be closed.
- In threads, all opened windows (like get_open_filename) are not blocking main game window.

Download (V2.0):
http://gmclan.org/up...GMThreads2.html (~9KB)
There's a simple example, DLL and the source code in the archive.

DLL is working only with GM6.1, GM7.0 and GM8.0

Edited by Snake_PL, 30 December 2009 - 09:28 AM.

  • 3

#2 Doogie_Forever

Doogie_Forever

    Dog Warrior

  • GMC Member
  • 811 posts
  • Version:GM:Studio

Posted 04 August 2008 - 11:35 AM

Holy crap this sounds awesome, me and my friend were literally talking today about how cool GM would be with threads, definitely gonna try this.

Edited by Doogie_Forever, 24 May 2010 - 02:11 PM.

  • 0

#3 gnysek

gnysek

    GMC Member

  • GMC Member
  • 339 posts
  • Version:GM:Studio

Posted 04 August 2008 - 11:41 AM

It's very helpful. Great work!
  • 0

#4 Doogie_Forever

Doogie_Forever

    Dog Warrior

  • GMC Member
  • 811 posts
  • Version:GM:Studio

Posted 04 August 2008 - 11:42 AM

I know I'm old fashioned and should upgrade but would there be any chance in this being coded for Game Maker 5.3a as well?

And if not making it open source so another may do so.

I tested this out, works really well. This is simply an ingenious idea.
  • 0

#5 Snake_PL

Snake_PL

    GMC Member

  • New Member
  • 57 posts

Posted 04 August 2008 - 11:56 AM

I know I'm old fashioned and should upgrade but would there be any chance in this being coded for Game Maker 5.3a as well?

Hmm... well, i'll try ;p

I tested this out, works really well. This is simply an ingenious idea.

Thanks.
  • 0

#6 freaked

freaked

    freak up!

  • New Member
  • 890 posts

Posted 04 August 2008 - 12:26 PM

Wow!
Great Job !
Any explanations as to how you achieved this via a DLL ?
  • 0

#7 gnysek

gnysek

    GMC Member

  • GMC Member
  • 339 posts
  • Version:GM:Studio

Posted 04 August 2008 - 12:37 PM

Maybe better question is why Mark Overmasrs said, that he will never put threads in Game Maker, because it will take too much time to write it... as we can see now, it's not to hard and takes a little time to write threading for GM.

Edited by gnysek, 04 August 2008 - 12:38 PM.

  • 0

#8 Robii

Robii

    GMC Member

  • New Member
  • 14 posts

Posted 04 August 2008 - 01:13 PM

Great DLL, Snake! ^_^ Make another useful DLL for us :D
  • 0

#9 nsm333

nsm333

    GMC Member

  • New Member
  • 230 posts

Posted 04 August 2008 - 01:16 PM

This is really useful! I've been looking for something like this. It solves one of my many problems!
  • 0

#10 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 04 August 2008 - 05:18 PM

This is nice. Thou how can I make it run every step? Or will it be even slower? Now the tread is executed one time. No function works to make it work more.

edit: btw, I always thought that treads in GM could be like surfaces. Something like tread_set_target(tread). Then the code to execute (like drawing for surfaces) and then tread_reset_target(). If it was built-in gm, then GM could be much faster don't you think? Things like AI, Physics and so on could be on different treads, and wouldn't it make the game run faster?

edit2: Why exactly can't the executed code get variables from local instance or some other ways? Because if global works, then why wouldn't any other variable type? Also, what exactly executes the code? GM with something like execute_string or the dll?

Edited by HaRRiKiRi, 04 August 2008 - 05:24 PM.

  • 0

#11 Yourself

Yourself

    The Ultimate Pronoun

  • Retired Staff
  • 7343 posts
  • Version:Unknown

Posted 04 August 2008 - 05:55 PM

Things like AI, Physics and so on could be on different treads, and wouldn't it make the game run faster?


Only on computers with multiple cores or processors. On single cores this will just serve to make the game slower.
  • 0

#12 Snake_PL

Snake_PL

    GMC Member

  • New Member
  • 57 posts

Posted 04 August 2008 - 06:10 PM

This is nice. Thou how can I make it run every step? Or will it be even slower? Now the tread is executed one time. No function works to make it work more.

Use "while" loop
thread = thread_create( "
  while (1) {
	// code
  }
", 0 );
// or
thread = thread_create( "
  while (1) {
	// code
	sleep( 1000 / room_speed );
  }
", 0 );

Why exactly can't the executed code get variables from local instance or some other ways?

Because code is not executed in any instance.

Also, what exactly executes the code? GM with something like execute_string or the dll?

GM ;p
  • 0

#13 nsm333

nsm333

    GMC Member

  • New Member
  • 230 posts

Posted 04 August 2008 - 06:17 PM

I can't seem to get something to work. How do I make it so that I can have a show_message, and then code being executed in another thread? It doesn't seem to do anything.
  • 0

#14 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 04 August 2008 - 06:45 PM

Only on computers with multiple cores or processors. On single cores this will just serve to make the game slower.

Thats what I wanted to say.

Use "while" loop

Ou, right. Sorry.

Because code is not executed in any instance.

Aa, but with () statement works as far as I know. So this isn't an issue.

GM ;p

Then this means two things.
1. We can use any variable we want, just using with statement.
2. This is kind of slow if used in continuation (every step). Because of the execute_string.

Does this support multiple cpu cores? I have core2duo, so can I make the tread to be executed on the other core? Because GM in default executes only on one core, and you can't change that.

There is a weird bug, sometimes the tread is not executed (skipping frames), so if the tread is for some movement calculations then the movement will be sluggish. Thou I guess this can be only used properly for loading in the background and stuff like that. This will allow proper loading screens, so thanks for this anyway.
  • 0

#15 gnysek

gnysek

    GMC Member

  • GMC Member
  • 339 posts
  • Version:GM:Studio

Posted 05 August 2008 - 07:34 AM

Huh, maybe if you want support of two cores, just write own application to write a game? Its just a Game Maker, and this DLL just helps to execute code in threads, no to optimize GM to super-ultra-high-supreme-speed application.
  • 0

#16 Blijbol

Blijbol

    Happy business

  • New Member
  • 312 posts

Posted 05 August 2008 - 09:49 AM

How in the world does your DLL execute GML code? Did you write your own GML interpreter?
  • 0

#17 gnysek

gnysek

    GMC Member

  • GMC Member
  • 339 posts
  • Version:GM:Studio

Posted 05 August 2008 - 10:07 AM

I don't think so. Looks, that compiled EMPTY exe weights about 2 MB, example game provided with this dll weights 17 kB, and this DLL weights 50kB - so it's much smaller than compiled game, which have interpreter, and not much bigger that game with so little code !
It must be another way.

Edited by gnysek, 05 August 2008 - 10:07 AM.

  • 0

#18 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 05 August 2008 - 03:19 PM

Huh, maybe if you want support of two cores, just write own application to write a game? Its just a Game Maker, and this DLL just helps to execute code in threads, no to optimize GM to super-ultra-high-supreme-speed application.

If he could make GM execute code in treads, then why couldn't he make them execute on a different cpu/core? I know that GM can't be optimized to super speed, but it can make it run faster. Treads is one of these ways.

How in the world does your DLL execute GML code? Did you write your own GML interpreter?

I don't think so. Looks, that compiled EMPTY exe weights about 2 MB, example game provided with this dll weights 17 kB, and this DLL weights 50kB - so it's much smaller than compiled game, which have interpreter, and not much bigger that game with so little code !
It must be another way.

He already stated that GM executes this code.
  • 0

#19 Sindarin

Sindarin

    Indie Game Developer

  • New Member
  • 1644 posts
  • Version:GM:HTML5

Posted 05 August 2008 - 05:14 PM

Snake? What have you done? Snaaaaake!!
This is really good. :blink:

Only on computers with multiple cores or processors. On single cores this will just serve to make the game slower.


But it won't crash the computer, right?
  • 0

#20 Potnop

Potnop

    GMC Member

  • GMC Member
  • 3101 posts

Posted 05 August 2008 - 05:45 PM

Cool. No it won't crash the computer, well it shouldn't. Multiple threads run on single core processors all the time. I think they have been since windows 95. It's the same idea as multiple processes running at the same time kinda...

Anyway...

How fast is this at executing the GML. Does it parse it itself and have to have all the runner code within itself or does it somehow use GM's runner code? And how would this work with extensions and stuff...
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users