Should I always call runtime.LockOSThread() before calling C function?

526 views
Skip to first unread message

ByeongJoon Gong

unread,
Oct 24, 2020, 1:30:53 PM10/24/20
to golang-nuts
Hi,
I'm developing speech-to-text inference server with cpp libraries (wav2letter)


"A goroutine should call LockOSThread before calling OS services or non-Go library functions that depend on per-thread state"

The current server process as fallow

func requestHandler(stream grpc....) {
  # runtime.LockOSThread()
  var decoder unsafe.Pointer
  init := false

  defer func() {
    if decoder != nil {
      C.resetDecoder(decoder)
    }
  }
  for {
    in, err := stream.Recv(); // grpc streaming
    if err != nil {
       break;
   }

   if init == true {
     C.decode(decoder, someTransformFunc(in.audio)) 
   } else {
     decoder = C.getDecoder()
     init = true
   }
  }
}

Even if I don't call runtime.LockOSThread(), it works.
but memory leak occured when repeated. 
( VmData keep increasing on /proc/{pid}/status )

If I call runtime.LockOSThread(), it works good and no memory leak.

why does a memory leak occur only when runtime.LockOSThread() is not called?



Ian Lance Taylor

unread,
Oct 24, 2020, 1:53:42 PM10/24/20
to ByeongJoon Gong, golang-nuts
We don't know because we don't know how the C code works. If it uses
per-thread state, then you need to call runtime.LockOSThread in Go.
But we don't know what it does. You'll need to look at the C code.

Ian

ByeongJoon Gong

unread,
Oct 25, 2020, 10:39:31 AM10/25/20
to golang-nuts
Thanks Ian

I found out that some libraries use thread-local storage
I understood that it should be called runtime.LockOSThread() in my go routine because each C function in for-loop can run on different thread

I have one more question.
If I called runtime.LockOSThread(), should I also call runtime.UnlockOSThread()?
When I called runtime.UnlockOSThread() in the end of go routine, heap usage increased.
I think thread-local storage's usage is accumulating because OS thread isn't terminated
Bacause of the above problem, I don't call runtime.UnlockOSThread() in the end of go routine.

2020년 10월 25일 일요일 오전 2시 53분 42초 UTC+9에 Ian Lance Taylor님이 작성:

Tamás Gulácsi

unread,
Oct 25, 2020, 2:20:42 PM10/25/20
to golang-nuts
I'd put all that C-calling code in ONE goroution, with runtime.LockOSThread, and send commands to this thread through a channel, with a receiver chan for response, too.
This way only one goroutine needs LockOSThread, and only that pays the memory penalty.
If it becomes the bottleneck, you can easily ramp up several such "C-facing-worker-goroutines".

Jesper Louis Andersen

unread,
Oct 26, 2020, 7:05:10 AM10/26/20
to Tamás Gulácsi, golang-nuts
On Sun, Oct 25, 2020 at 7:20 PM Tamás Gulácsi <tgula...@gmail.com> wrote:
I'd put all that C-calling code in ONE goroution, with runtime.LockOSThread, and send commands to this thread through a channel, with a receiver chan for response, too.
This way only one goroutine needs LockOSThread, and only that pays the memory penalty.
If it becomes the bottleneck, you can easily ramp up several such "C-facing-worker-goroutines".


I'd do this too.

If not for anything else, it is a good foundation from which to start. Once you know more about the behavior of the system, you can try to lessen up the constraints, but chances are you don't have to ever. It depends on the use case.

Reply all
Reply to author
Forward
0 new messages