Hi,
I use setControlCHook to handle the close of a sqlite db, after doing some logs about running time.
I moved to Nim 1.4, and in the same time I add a thread to my code, in fact this is a web sever, but there is a background task that handle CPU demanding work (zip of thousands of file and so on).
I've got something like :
...
var
t : Thread[int32]
...
proc handler() {.noconv.} =
# ... do db stuff
db.close()
joinThread(t)
quit 0
...
proc init()=
...
setControlCHook(handler)
proc main()=
createThread(t, handleThread, int32(0)) # define elsewhere
waitFor server1.serve(Port(port), cb) # define elsewhere
init()
main()
in fact, handler is not called anymore when Ctrl C is hit, as it was before, I've checked, it does not seem related to thread, because if I comment it, it does not work either
I alse didn't find how to defined a thread proc that take no argument, if anyone know?
May be having a background worker thread could be done in a better way, any idea?
It's either your code, or your nim version. I'm using 1.5x and a MWE test passed for me.
import asynchttpserver, asyncdispatch
var server = newAsyncHttpServer()
proc cb(req: Request) {.async.} =
await req.respond(Http200, "Hello World")
var t:Thread[int32]
proc handleThread(i:int32) {.thread.} =
echo "hi from thread"
proc ctrl_c_handler() {.noconv.} =
echo "ctrl-c hook invoked"
joinThread(t)
quit 0
proc init =
setControlCHook(ctrl_c_handler)
proc main =
createThread(t, handleThread, int32(0)) # define elsewhere
waitFor server.serve(Port(9090), cb)
init()
main()
@ggibson : I tried your code and with nim 1.4.6, ctrl_c_handler is not called, under Windows 10
I am not sure to be clear. So let's try to explain it another way:
I have a web server in the main thread, that uses a sqllite db
I need to create a thread as a background worker that do heavy work, in fact the web server, when asked, set some flags and work in the db, and the background thread handle the work
I just need that when Ctrl C happens, all close nicely, the db and the worker thread, may be I doing it completly wrong, if so how to do it the good way?
I think this is what Araq meant:
import std/[atomics, os]
var shouldRun: Atomic[bool]
shouldRun.store(true)
type
ThreadArg = tuple[name: string, argint: int]
proc stop*() {.noconv.} =
echo("SIGINT receive")
shouldRun.store(false)
proc runLoop*(arg: ThreadArg) =
echo "runLoop -- BEGIN"
echo "dbOpen()"
while shouldRun.load():
echo(arg.name & " is doing stuff")
sleep(1_000)
echo "dbClose"
echo "runLoop -- END"
proc main() =
setControlCHook(stop)
var thr : Thread[ThreadArg]
var threadArg = ("ThreadName", 12)
createThread(thr, runLoop, threadArg)
echo "main() can keep doing stuff too !"
echo "Ok, main is done now. Let's wait for the end of the thread"
joinThread(thr)
echo "Bye-bye"
when isMainModule:
main()
Use an atomic boolean to exit your polling / while loop inside your thread so you can exit the thread properly and have your main function wait for the thread to end with joinThread.
This is how I would it, anyway.
I definitely don't meant:
proc stop*() {.noconv.} =
echo("SIGINT receive")
shouldRun.store(false)
As you cannot use echo either in a signal handler. ;-)