Threads in 0.9.0?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- OmarShehata
- Party member
- Posts: 259
- Joined: Tue May 29, 2012 6:46 pm
- Location: Egypt
- Contact:
Threads in 0.9.0?
I'm having some trouble understanding how threads/channels work in 0.9.0
So I get that there's the Channel API to communicate with threads, but I don't get how to "link" a channel with a thread.
I create a new thread with http://www.love2d.org/wiki/love.thread.newThread, and a new channel with http://www.love2d.org/wiki/love.thread.newChannel or getChannel...and then what? How do I tell it that Channel belongs to that thread..? Any examples on how to use it?
So I get that there's the Channel API to communicate with threads, but I don't get how to "link" a channel with a thread.
I create a new thread with http://www.love2d.org/wiki/love.thread.newThread, and a new channel with http://www.love2d.org/wiki/love.thread.newChannel or getChannel...and then what? How do I tell it that Channel belongs to that thread..? Any examples on how to use it?
- bartbes
- Sex machine
- Posts: 4946
- Joined: Fri Aug 29, 2008 10:35 am
- Location: The Netherlands
- Contact:
Re: Threads in 0.9.0?
There is no direct relationship between channels and threads. Channels are basically thread-safe, shared queues. There are two kinds of channels, with subtly different mechanics.
Named channels: These keep their contents even without references, and are available globally, using getChannel. They also get created when they don't exist yet, so just calling getChannel with a non-existent name gives you a fresh one. (Technically, they are also destructed when they are empty, and there are no references, but that's not important.)
Unnamed channels: These get collected normally, and you can only obtain them from newChannel once. If you want to use it in multiple places, you need to find a way to get them there, like the new parameters to [wiki]Thread:start[/wiki], or sending them over another channel.
Of course this doesn't mean you can't pass named channels around, it's just that there's a central "registry" for them.
Named channels: These keep their contents even without references, and are available globally, using getChannel. They also get created when they don't exist yet, so just calling getChannel with a non-existent name gives you a fresh one. (Technically, they are also destructed when they are empty, and there are no references, but that's not important.)
Unnamed channels: These get collected normally, and you can only obtain them from newChannel once. If you want to use it in multiple places, you need to find a way to get them there, like the new parameters to [wiki]Thread:start[/wiki], or sending them over another channel.
Of course this doesn't mean you can't pass named channels around, it's just that there's a central "registry" for them.
Code: Select all
-- main
t = love.thread.newThread("thread.lua")
c1 = love.thread.newChannel()
c2 = love.thread.getChannel("cookie")
t:start(c1)
c2:supply(c1:demand())
-- thread
c1 = ...
c2 = love.thread.getChannel("cookie")
c1:supply("Hello, world!")
c2:push(c1:demand())
- OmarShehata
- Party member
- Posts: 259
- Joined: Tue May 29, 2012 6:46 pm
- Location: Egypt
- Contact:
Re: Threads in 0.9.0?
Thanks for the quick reply bartbes! I just got it to work.
-
- Party member
- Posts: 712
- Joined: Fri Jun 22, 2012 4:54 pm
- Contact:
Re: Threads in 0.9.0?
This looks really difficult compared to the old thread:send, thread:demand and thread:get methods..bartbes wrote:Code: Select all
-- main t = love.thread.newThread("thread.lua") c1 = love.thread.newChannel() c2 = love.thread.getChannel("cookie") t:start(c1) c2:supply(c1:demand()) -- thread c1 = ... c2 = love.thread.getChannel("cookie") c1:supply("Hello, world!") c2:push(c1:demand())
Can you name some advantages? Why was the API changed so much?
trAInsported - Write AI to control your trains
Bandana (Dev blog) - Platformer featuring an awesome little ninja by Micha and me
GridCars - Our jam entry for LD31
Germanunkol.de
Bandana (Dev blog) - Platformer featuring an awesome little ninja by Micha and me
GridCars - Our jam entry for LD31
Germanunkol.de
- bartbes
- Sex machine
- Posts: 4946
- Joined: Fri Aug 29, 2008 10:35 am
- Location: The Netherlands
- Contact:
Re: Threads in 0.9.0?
That's a convoluted example, it's not harder, and in fact has way less edge cases and gotchas.
Re: Threads in 0.9.0?
Allow me to revive this thread to throw into the hat the not-so-convoluted example of how to use love.thread:
Does it look pretty? Eh, maybe not.
Does it work? You bet your muffins.
Code: Select all
-- main.lua
function love.load()
thread = love.thread.newThread("thread.lua")
channel = love.thread.getChannel("test")
thread:start()
i = {}
end
function love.update(dt)
v = channel:pop()
if v then
table.insert(i, v)
end
end
function love.draw()
love.graphics.print(tostring(i[1]), 10, 10)
end
-- thread.lua
c = love.thread.getChannel("test")
c:push("hi")
Does it work? You bet your muffins.
"Bump." -CMFIend420
Re: Threads in 0.9.0?
Is there a preferred way to implement locks? I think blocking with :demand() on a named channel should do the trick but maybe there's something better I'm not aware of.
It would be nice to save a thread-specific value in the lock that identifies the thread that obtained the lock though.
Edit: more questions:
2. :demand() is implemented in "smart" C++ (vs. long polling), right?
3. Can I somehow build an atomic "tryDemand" method?
If I want to synchronize two threads that work on one array-table of objects, I would write something like this:
However this is not thread safe, both threads could check getCount() at the same time, then one of them obtains the lock whilst the other thread is blocked for the whole update, after which it proceeds to update the same object a second time. The double-updating can be prevented with a simple flag, but this still wastes quite some time, especially if the list is long and this happens quite often.
Code: Select all
-- create Lock
lock = love.thread.getChannel( lockname )
lock:push(-1) -- message = free
-- obtain lock
lock:demand() -- pop the free message or wait for it
-- do something
-- release lock
lock:push(-1)
Edit: more questions:
2. :demand() is implemented in "smart" C++ (vs. long polling), right?
3. Can I somehow build an atomic "tryDemand" method?
If I want to synchronize two threads that work on one array-table of objects, I would write something like this:
Code: Select all
for _,v in ipairs( sharedtable ) do
if sharedtable.lock:getCount() > 0 then
sharedtable.lock:demand() -- obtain
-- do stuff
sharedtable.lock:push(-1) -- release
end
end
Re: Threads in 0.9.0?
And here we go, found a possible answer by myself (3.):
Non-blocking locks can be done like this:
Aaaaand the first actual problem: If I may only supply flat tables (via Thread.run and channels), how do I make threads cooperatively work on a list of entities?
Non-blocking locks can be done like this:
Code: Select all
-- in the "scheduler" thread7
update = not (update or true)
-- each thread:
for _,v in ipairs(sharedtable) do
if v.lock:pop() ~= update then -- if the lock has been obtained this returns nil, if it has already been updated it returns update
-- do something
end
l.lock:push( update ) -- flag object as done
end
Re: Threads in 0.9.0?
I believe the limit for number of channels is pretty high.S0lll0s wrote:how do I make threads cooperatively work on a list of entities?
Would be pretty hilarious to send a flat table full of channels, each channel representing a single table index.
Re: Threads in 0.9.0?
that could actually.... work xDAzhukar wrote:I believe the limit for number of channels is pretty high.S0lll0s wrote:how do I make threads cooperatively work on a list of entities?
Would be pretty hilarious to send a flat table full of channels, each channel representing a single table index.
Code: Select all
local meta = love.thread.getChannel("meta")
local keys = {}
for k,v in pairs( ent ) do
love.thread.getChannel(k):push(v)
keys[#keys+1] = k
end
meta:supply( keys )
for _,k in ipairs( keys ) do
love.thread.getChannel(k):clear()
end
Who is online
Users browsing this forum: Ahrefs [Bot] and 3 guests