Hi. How to get value of object's field from second thread? For example server.nim:
...
type
Server* = ref object
socket: AsyncSocket
started*: bool
...
...
proc newServer*(): Server =
Server(
socket: nil,
false,
...
)
proc loopThr(server: Server, serverPort: int) =
server.socket = newAsyncSocket()
server.socket.bindAddr(serverPort.Port)
server.socket.listen()
server.started = true
server.loopTask = loop(server)
waitFor server.loopTask
proc start*(server: Server, serverPort: int) =
spawn loopThr(server, serverPort)
sleep(100)
...
main.nim:
...
var srv: Server
srv = newServer()
srv.start(port)
echo serv.started
...
will show "false" How to pass values of fields between threads?How to do it correctly and, probably, elegantly? (sorry, but constructions like this looks a bit mad for this easy task :-| I tried something like a:
import os, threadpool
type
MyObj = object
flag: bool
proc subThr(pObj: ptr MyObj) {.gcsafe.} =
pObj.flag = true
var pShr = cast[ptr MyObj](allocShared0(sizeof(MyObj)))
var o: MyObj = pShr[]
o.flag = false
spawn subThr(pShr)
sleep 100
echo o.flag
But it's don't write data by pointer. Maybe somebody have ideas?I think I should note that I'm not sure if you really intended using async* with threadpools. Async stuff in Nim is still single threaded (even though its concurrent, it is not parallel).
You should instead use a single-threaded program, declare loopThr as {.async.} and then use await in loopThr.
Please let me know if you need any help with the async stuff, it can indeed be a bit weird...
I can't test this now, but try:
type
Server* = ref object
socket: AsyncSocket
started*: bool
...
...
proc newServer*(): Server =
Server(
socket: nil,
false,
...
)
proc loopThr(server: Server, serverPort: int) {.async.} =
server.socket = newAsyncSocket()
server.socket.bindAddr(serverPort.Port)
server.socket.listen()
server.started = true
# server.loopTask = loop(server) # not sure what this is here
# waitFor server.loopTask # you can do some non-blocking IO now. eg:
let line = await server.socket.recvLine() # this will not block
proc start*(server: Server, serverPort: int) =
waitFor loopThr(server, serverPort) # changed this to ``waitFor`` for example's sake.
sleep(100)
Oops.
loopThr needs a loop, or the program will exit immediately.
For simply passing value, use channels .
Looking at your case, I guess you should use channels. You have two separate thread, first is qml thread and 2nd server thread.
Using channel, you can apply producer-consumer pattern to both.
Thanks, I saw your examples in previous posts with similar theme (I've posted link before). Well, I did "simple" application, who demonstrate exchanging process of object between two threads. This model looks it is logical, but code for this task looks really mad and inflexible :-| (for 21th), sorry:
import os, threadpool
type
SharedChannel[T] = ptr Channel[T]
proc newSharedChannel[T](): SharedChannel[T] =
result = cast[SharedChannel[T]](allocShared0(sizeof(Channel[T])))
open(result[])
proc close[T](ch: var SharedChannel[T]) =
close(ch[])
deallocShared(ch)
ch = nil
proc send[T](ch: SharedChannel[T], content: T) =
ch[].send(content)
proc recv[T](ch: SharedChannel[T]): T =
result = ch[].recv
type
MyObj = ref object
flag: bool
proc someThread(ch: SharedChannel[MyObj]) {.thread.} =
var obj = ch.recv
if obj != nil:
echo obj.flag
obj.flag = false
ch.send(obj)
var
ch = newSharedChannel[MyObj]()
spawn someThread(ch)
var obj: MyObj
obj.new()
obj.flag = true
ch.send(obj)
sleep 500
obj = ch.recv
echo obj.flag
close(ch)
Now I'll figure out how best to integrate this model into the application. Also I'll play with the global variables and locking, maybe I'll find more easy way. Thanks for all for your help and discussion!well, "--threadAnalysis:off"+globalvar+lock looks nice:
import os, threadpool, locks
type
MyObj = ref object
flag: bool
var olock: Lock
var obj {.guard: olock.}: MyObj
proc someThread() {.gcsafe.} =
{.locks: [olock].}:
if obj != nil:
echo obj.flag
obj.flag = false
obj.new()
obj.flag = true
spawn someThread()
sleep 500
echo obj.flag