Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
  • Announcements

    • Lizzy Trickster

      Latest Stable OpenComputers Version   11/26/16

      The latest released version of OpenComputers is version 1.7.1 for MC 1.7.10, 1.10.2, 1.11.2 & 1.12.1. See more information here! Beta/Dev builds can be found at the Jenkins Build Server (ci.cil.li)
  • 0
thearhar

Create infinite thread in background and continue

Question

What I'm trying to do is IC2 reactor control with some graphic interface: 


It draws components durability status, contorls overheating and reads event from keyboard to switch power.
But what happening now is until it draw all components, that takes forever and is painfully slow, it will not react to any event, and will not check overheating
What I want to do is create thread that draws components and continue main program to listen events and check overheating
Now I have this code: https://pastebin.com/BBw1TxYd

I tried to use threads api, but it seems you can not create infinite while-true-loop thread and continue main function:
 

td=thread.create(function()
  while true do
    checkDmg()
  end
end):detach()

--NEVER GETS HERE

while handleEvent(event.pull(1)) do
  --nothing
end

** I cant understand nothing about what detach actually do, documentation needs to be extended

As I understand, there is absolutely no way to do what I'm trying to do in lua?
Basically I need to be able to interrupt my code that draws things at any moment by pressing key

Share this post


Link to post
Share on other sites

6 answers to this question

Recommended Posts

  • 1

Btw if you want to speed up the drawing process, here are some tips:

A gpu can only perform a small amount of tasks each tick. 4 copy, 8 fill, 16 set, 8 setBackground and 8 setForeground; if you call more of these funtions, they are delayed, and it seems that you call a ton of these funtions. For example instead of using gpu.fill in order to set  a single character use gpu.set() since you can call it 16 times per tick. And if you want to fill a line in x direction with a string like "/" you can use gpu.set(x,y,string.rep("/", n)); the string "/" is replicated n times. This can also reduce the amount of fill commands and speeds up drawing. Using gpu.copy would increase your drawing speed the most. This copies one area of the screen and pastes it to a different area. So you would draw one of each objects on your screen, without the damage bar. Then you would copy the objects to all the desired locations and draw the damage bar. That way you wold be able to draw 80 objects per second, so a lot faster than you are currently be able to.

Share this post


Link to post
Share on other sites
  • 1

@thearhar Please, if you have specific feedback for ocdoc, add your suggestion to https://github.com/MightyPirates/OpenComputers/issues/2686

As for detach I can see that its explanation was a bit short. It would have been easier to understand if you read the entire doc. I have updated the explanation for detach in the docs

From the docs, it is explained that a thread is attached to the current process when created. An attached thread blocks the parent process from closing until that thread dies. A parent process can abort, which kills all attached threads.A detached thread blocks no process (technically, the init process is its parent, but it does not block reboot/shutdown)

 

Share this post


Link to post
Share on other sites
  • 0

Threads are just fancy coroutines. This means that they still have to obey and yield like any other process, coroutine, or block of code. All blocks must yield or finish execution in a 5 seconds or they are terminated. Looking into your code as it's arranged now I would suggest yielding once or perhaps several times throughout the checkDmg function depending on the drawing performance. Here would be my two suggested alterations..

function checkDmg()
  local dmg=0
  for i=1,li-1,1 do
    if inv.getStackInSlot(2,lzhs[i][3]) then
      dmg=inv.getStackInSlot(2,lzhs[i][3]).customDamage
      fillDmg(lzhs[i][1],lzhs[i][2],"LZH",dmg)
    else
      fillDmg(lzhs[i][1],lzhs[i][2],"LZH",100000)
    end
    coroutine.yield()
  end  
  local r
  for i=1,ri-1,1 do
    r=inv.getStackInSlot(2,rods[i][3])
    if r and not string.match(r.label,"Depleted") then
      dmg=inv.getStackInSlot(2,rods[i][3]).customDamage
      fillDmg(rods[i][1],rods[i][2],"Rod",dmg)
    else
      fillDmg(rods[i][1],rods[i][2],"Rod",20000)
    end
    coroutine.yield()
  end  
  for i=1,vi-1,1 do
    if inv.getStackInSlot(2,vents[i][3]) then
      dmg=inv.getStackInSlot(2,vents[i][3]).customDamage
      fillDmg(vents[i][1],vents[i][2],"Vent",dmg)
    else
      fillDmg(vents[i][1],vents[i][2],"Vent",1000)
    end
    coroutine.yield()
  end  
end
td=thread.create(function()
  while true do
    checkDmg()
    os.sleep(0) --# sleep will yield this process/thread and resume asap allowing the 'following block' to begin execution.
  end
end) -- # no need to detach unless you really want this to continue after your program is dead..

-- # the 'folowing block'
print "Now executing main block..."
while true do
  local _continue = handleEvent(event.pull())
  -- # do shit
end

The first example yields the 'td' thread once for every cycle of each inner loop. Mostly because of the drawing and the inv component calls. This costs time! So we yield and allow the event loop below to begin. This is my recommended solution although untested. The second example will yield the 'td' thread once after each call to checkDmg. This could work fine but I suspect the first option will perform better / be more responsive to events.

Lemme know how it goes and if I can help anymore.

Share this post


Link to post
Share on other sites
  • 0

great advice and explanation @Molinko thank you for supporting the community!

One small change I would recommend: When working with user programs or threads (as opposed to custom coroutines) don't use coroutine.yield() unless you SPECIFICALLY want your process to block until a SIGNAL is raised (e.g. key_down)

coroutine.yield() blocks until it receives a signal, even in threads

os.sleep(0) might be better

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×