Re: Can goroutine switch thread while calling C function

1,324 views
Skip to first unread message

David DENG

unread,
Feb 8, 2013, 11:17:32 PM2/8/13
to golan...@googlegroups.com, kir...@apcera.com
What do you mean "it will execute in the same OS thread"? Why depending on this?

David

On Saturday, February 9, 2013 11:39:28 AM UTC+8, kir...@apcera.com wrote:
Cannot find a definitive answer, I suspect the answer is "yes" but would like a guarantee.

Is it true that a goroutine cannot switch a thread while it is calling a C function via CGO?

I.e. in a C function called from Go I can rely on the fact that it will execute in the same OS thread regardless of what it does (running for long, making blocking calls etc)?

Thanks.

Kyle Lemons

unread,
Feb 8, 2013, 11:21:29 PM2/8/13
to kir...@apcera.com, golang-nuts
The runtime cannot do anything with a thread whose instruction pointer is in some C code.  So no, between when cgo calls your function and when the function returns, it cannot change OS threads.  Before and after the call, however, all bets are off (and subsequent calls may well be from another os thread).

Unless I'm very mistaken.


On Fri, Feb 8, 2013 at 7:39 PM, <kir...@apcera.com> wrote:
Cannot find a definitive answer, I suspect the answer is "yes" but would like a guarantee.

Is it true that a goroutine cannot switch a thread while it is calling a C function via CGO?

I.e. in a C function called from Go I can rely on the fact that it will execute in the same OS thread regardless of what it does (running for long, making blocking calls etc)?

Thanks.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Kevin Gillette

unread,
Feb 8, 2013, 11:26:06 PM2/8/13
to golan...@googlegroups.com, kir...@apcera.com
You can call runtime.LockOSThread to force a goroutine (and any C calls it makes) to be from one thread.

minux

unread,
Feb 9, 2013, 7:37:50 AM2/9/13
to kir...@apcera.com, golan...@googlegroups.com
On Sat, Feb 9, 2013 at 11:39 AM, <kir...@apcera.com> wrote:
Cannot find a definitive answer, I suspect the answer is "yes" but would like a guarantee.

Is it true that a goroutine cannot switch a thread while it is calling a C function via CGO?
right, before calling C code the runtime will lock the current goroutine on the current OS thread. 

I.e. in a C function called from Go I can rely on the fact that it will execute in the same OS thread regardless of what it does (running for long, making blocking calls etc)?
right. as long as it doesn't call Go callbacks from another thread created by C code
(not supported yet).

Peter Kleiweg

unread,
Feb 10, 2013, 6:38:47 AM2/10/13
to golan...@googlegroups.com, kir...@apcera.com
Op zaterdag 9 februari 2013 05:26:06 UTC+1 schreef Kevin Gillette het volgende:

You can call runtime.LockOSThread to force a goroutine (and any C calls it makes) to be from one thread.

So, safe cgo code should look something like this:

     // make sure the two C calls run in the same thread
     runtime.LockOSThread()
     foo := C.foo_init() // sets global C variable
     err := C.foo_err() // reads global C variable
     runtime.UnlockOSThread()

     // free C resources before foo is garbage collected
     runtime.SetFinalizer(&foo, (*Foo).Free)

I think this should be in the main documentation, and on the wiki.

 

Maxim Khitrov

unread,
Feb 10, 2013, 8:48:29 AM2/10/13
to Peter Kleiweg, golan...@googlegroups.com, kir...@apcera.com
Could you explain why LockOSThread/UnlockOSThread are necessary here?
What would be unsafe about omitting these two calls?

- Max

Peter Kleiweg

unread,
Feb 10, 2013, 9:40:12 AM2/10/13
to golan...@googlegroups.com, Peter Kleiweg, kir...@apcera.com
Op zondag 10 februari 2013 14:48:29 UTC+1 schreef Maxim Khitrov het volgende:
If I understand correctly, another thread could call the same C.foo_init(), setting some global C variable to another value, before C.foo_err() in the current thread could read it.

Peter Kleiweg

unread,
Feb 10, 2013, 9:49:39 AM2/10/13
to golan...@googlegroups.com, Peter Kleiweg, kir...@apcera.com


Op zondag 10 februari 2013 15:40:12 UTC+1 schreef Peter Kleiweg het volgende:
Or should I use  sync.Mutex Lock()/Unlock() instead?

Maxim Khitrov

unread,
Feb 10, 2013, 10:13:41 AM2/10/13
to Peter Kleiweg, golan...@googlegroups.com, kir...@apcera.com
I'm not exactly sure what your assumptions are. If you only have one
goroutine, I don't think you need anything around foo_init and
foo_err.

If I understood minux correctly, all calls into C are performed using
the same thread that was executing the goroutine. If you had more than
one goroutine active, then the Go runtime may spawn additional threads
to run those goroutines, while yours is in C. If those goroutines also
call foo_init and foo_err, then a mutex would be appropriate.

If the C code calls back into Go, the Go functions continue to run on
the same thread and cannot switch to any other (as though
runtime.LockOSThread() was called before the original cgo call). The
only exception to this is if the C code decides to run the callback
from another C thread.

- Max

Ian Lance Taylor

unread,
Feb 10, 2013, 12:52:23 PM2/10/13
to Peter Kleiweg, golan...@googlegroups.com, kir...@apcera.com
On Sun, Feb 10, 2013 at 3:38 AM, Peter Kleiweg <pkle...@xs4all.nl> wrote:
> Op zaterdag 9 februari 2013 05:26:06 UTC+1 schreef Kevin Gillette het
> volgende:
>
>> You can call runtime.LockOSThread to force a goroutine (and any C calls it
>> makes) to be from one thread.
>
>
> So, safe cgo code should look something like this:
>
> // make sure the two C calls run in the same thread
> runtime.LockOSThread()
> foo := C.foo_init() // sets global C variable
> err := C.foo_err() // reads global C variable
> runtime.UnlockOSThread()

That does not look right to me. You might need a mutex here. But I
don't think you need LockOSThread.

The time you need LockOSThread is when calling C code that uses
thread-local variables. You don't need it for ordinary global
variables.

Ian

minux

unread,
Feb 10, 2013, 12:56:56 PM2/10/13
to Peter Kleiweg, golan...@googlegroups.com, kir...@apcera.com
this is a data race, and LockOSThread won't help, you must use a Mutex or other synchronization
primitive to protect the global C state. 

minux

unread,
Feb 10, 2013, 1:09:43 PM2/10/13
to Maxim Khitrov, Peter Kleiweg, golan...@googlegroups.com, kir...@apcera.com
On Sun, Feb 10, 2013 at 11:13 PM, Maxim Khitrov <m...@mxcrypt.com> wrote:
If I understood minux correctly, all calls into C are performed using
the same thread that was executing the goroutine. If you had more than
right.
 
one goroutine active, then the Go runtime may spawn additional threads
to run those goroutines, while yours is in C. If those goroutines also
call foo_init and foo_err, then a mutex would be appropriate.

If the C code calls back into Go, the Go functions continue to run on
the same thread and cannot switch to any other (as though
runtime.LockOSThread() was called before the original cgo call). The
only exception to this is if the C code decides to run the callback
from another C thread.
and currently cgo doesn't allow a foreign thread (those started by C code) to
call Go callback functions. this is https://code.google.com/p/go/issues/detail?id=4435.
Reply all
Reply to author
Forward
0 new messages