thread:pause() ?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Luke100000
Party member
Posts: 232
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

thread:pause() ?

Post by Luke100000 »

I'm working on a game, where the player can write own code into an virtual computer. Because the main-loop should not stop, a thread is needed. The virtual computers are slow, ~1 MHz. To control them I have an extra thread who only controls all the computers.

Code: Select all

while true do
    local time = os.clock()
    for i = 1, #threads do
        threads[i]:start()
        love.timer.sleep(virtualCPUspeed / realCPUspeed)
        threads[i]:pause() --And here's the problem, there is no pause.
    end
    love.timer.sleep(1 - (os.clock - time) )
end
The computers have every second some time to do their work.

Sorry for my English, I think I made some spelling errors :D
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: thread:pause() ?

Post by Nixola »

You should implement sleeping inside the thread itself, not outside of it. The thread can't be controlled directly from the outside, you've got to control it from within itself.
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
slime
Solid Snayke
Posts: 3166
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: thread:pause() ?

Post by slime »

[wiki]Channel:demand[/wiki], [wiki]Channel:supply[/wiki], and [wiki]love.timer.sleep[/wiki] will all pause the thread the functions are called from (until the condition is met.) As Nixola mentioned, you'll need to do it from inside the thread's code rather than outside.

It's also generally a good idea to do a while-loop from inside the thread's code rather than constantly restarting it, since starting a thread is very expensive compared to just continuing a loop (and that gives you a great place to use the above functions to pause the thread.)
User avatar
Luke100000
Party member
Posts: 232
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

Re: thread:pause() ?

Post by Luke100000 »

How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!

Can I yield a coroutine automatically after time? Something like this: coroutine:resume(forSeconds)
User avatar
Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

Re: thread:pause() ?

Post by Xgoff »

Luke100000 wrote:How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!
unless this is a server program, i wouldn't worry too much about the user shooting their own foot
Can I yield a coroutine automatically after time? Something like this: coroutine:resume(forSeconds)
well, yes and no. unlike pre-emptive threads, coroutines have full control over their own yielding. you *could* write wrappers around the coroutine functions that cause a coroutine to yield itself automatically after some time period, but it will still be vulnerable to infinite loops or even long-running code, again because coroutines are not pre-emptive
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: thread:pause() ?

Post by Robin »

Actually, now that I think of it, Kikito has written a sandbox library that limits the time a function can run. It might be something you can use.
Help us help you: attach a .love.
User avatar
Luke100000
Party member
Posts: 232
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

Re: thread:pause() ?

Post by Luke100000 »

OK that's maybe a stupid idea: When the player launch the code, it will create a special love.timer.sleep() in front of every end/else/elseif.

Something like this:

--- original code

Code: Select all

local a = 0
while true do
   if a < 100 then
      a = a + 1
   else
      a = 0
   end
end
-- code after launching

Code: Select all

local a = 0
while true do
   if a < 100 then
      a = a + 1
      wait()
   else
      a = 0
      wait()
   end
   wait()
end
It should work. :awesome:

Xgoff wrote:
Luke100000 wrote:How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!
unless this is a server program, i wouldn't worry too much about the user shooting their own foot
It's not a server, but there are different in-game-computer with different speed.

Xgoff, did you write "OBEY" in hexadecimal on your avatar? :awesome:

Robin wrote:Actually, now that I think of it, Kikito has written a sandbox library that limits the time a function can run. It might be something you can use.
Yeah that's great. The player can create short lag spikes but it's something I was looking for. At first.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: thread:pause() ?

Post by Robin »

Luke100000 wrote:OK that's maybe a stupid idea: When the player launch the code, it will create a special love.timer.sleep() in front of every end/else/elseif.
That sounds exploitable.

If you implement that, I'd like to take a look at that, see if I can find ways to abuse it. :)
Help us help you: attach a .love.
User avatar
Luke100000
Party member
Posts: 232
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

Re: thread:pause() ?

Post by Luke100000 »

Code: Select all

local lastTime = false
local timewhenstarted = love.timer.getTime()
local time = 0

local CPUspeed = 20 --MHz, the virtual-computer
local realCPUspeed = 3 * 3200 --MHz, my computer

local sleepAfter = CPUspeed / realCPUspeed

function wait()

	local microtime = love.timer.getTime()
	if lastTime then
		time = time + ( microtime - lastTime )
		if time > sleepAfter then
			love.timer.sleep( sleepAfter * ( realCPUspeed / CPUspeed - 1 ) )
			microtime = microtime + sleepAfter * ( realCPUspeed / CPUspeed - 1 )
			time = time - sleepAfter
		end
	end
	
	lastTime = microtime
	if microtime - timewhenstarted > 10 then
		print( "loops per second: " .. math.floor( a/10 ) .. "\n" )
		os.exit()
	end
	
end

function transformCode(code)
	local i = 0
	local functname = "wait()"
	local commandsToCheck = {"end", "else", "elseif"}
	local string = code
	
	for i,v in ipairs(commandsToCheck) do
		while true do
			i, j = string.find(string .. " ", v, i + 2 + #functname)
			if i == nil then
				break
			end
			string = string.sub(string, 1, i - 1) .. functname .. " " .. string.sub(string, i, #string)
		end
	end
	
	--remove all \n
	while true do
		i, j = string.find(string, "\n")
		if i == nil then
			break
		end
		string = string.sub(string, 1, i-1) .. " " .. string.sub(string, i+1, #string)
	end
	
	return string
end

local original_code = "a = 0\nwhile true do\n    a = a + 1\nend"

local code = transformCode( original_code .. " " )

print("\nORIGINALCODE:\n" .. original_code .. "\n\nCODE:\n" .. code .. "\n")

local func, msg =  pcall( loadstring( code ) )

if func then
	func()
else
	print("ERROR: " .. msg)
end
original_code is the code which can be written by the player. Because the player can write several lines, my "transformCode()" delete all "\n"
realCPUspeed is your PC, I need a library to check this automatically :(
CPUspeed is the speed of the ingame-computer. I type 20 MHz, this is very slow.
For this example, I will stop the code in the wait() function and print out the progress.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: thread:pause() ?

Post by Robin »

Why do you remove all \n, tough?

Also, both adding wait() and removing \n could be done with simply calling [manual]string.gsub[/manual] instead of those expensive
Also:

Code: Select all

function wait() end
local a = 0
while true do
   if a < 100 then
      a = a + 1
   else
      a = 0
   end
end
Also, this way I can't use return anywhere, I don't know if that's intended.
Help us help you: attach a .love.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot], Hugues Ross and 10 guests