Update: after manually clearing dispatcher's `callbacks` and `timers` and 
manually calling a GC the memory is properly freed, even when the `cycle` 
coroutine is still pending. So the question is: why do I have to do this 
manually? Shouldn't this be done automatically when the thread finishes?

The properly working code is below:
    
    
    import std/asyncdispatch
    import HeapQueue, deques
    
    
    type MyObj = object
      value: ptr int
    
    proc `=destroy`(x: MyObj) =
      if x.value == nil:
        return
      dealloc(cast[pointer](x.value))
      echo "memory deallocated"
    
    proc newMyObj(x: int): MyObj =
      result.value = cast[ptr int](alloc0(100_000_000*sizeof(int)))
      echo "memory allocated"
      
      let p = cast[ptr UncheckedArray[int]](result.value)
      for i in 0..<100_000_000:
        p[i] = x + i
    
    proc cycler(x: ref MyObj) {.async.} =
      while true:
        x.value[] += 1
        echo x.value[]
        await sleepAsync(200)
    
    proc main_async() {.async.} =
      let x = new(MyObj)
      x[] = newMyObj(3)
      let fut = cycler(x)
      await sleepAsync(1000)
    
    proc main() {.thread.} =
      echo "thread started"
      waitFor(main_async())
      echo "thread finished"
      
      let p = getGlobalDispatcher()
      p.callbacks.clear()
      p.timers.clear()
      GC_fullCollect()
    
    while true:
      var th = Thread[void]()
      createThread(th, main)
      joinThreads(th)
    
    
    Run

Reply via email to