27

Golang supports LockOSThread() to make current goroutine exclusively tied to current OS thread, and it can also UnlockOSThread().

Are there any use cases that benefit from this feature?

Hymns For Disco
  • 7,530
  • 2
  • 17
  • 33
Jason Xu
  • 2,903
  • 5
  • 31
  • 54
  • 2
    Let's say you have 8 processor threads and 16 goroutines. This means that there are on average two goroutines per real thread. Now if you're building something real-time, you want to be able to run code as soon as possible and avoid the matching of goroutines to threads, you don't want your real time code to get 'behind' less important code. This can solve priority inversion problems etc. Although schedular activations can mitigate this. – Benjamin Gruenbaum Aug 18 '14 at 11:08
  • 2
    A good example of using this function can be found in http://golang.org/src/pkg/net/lookup_windows.go . I'd recommend doing a google search for "lockosthread site:golang.org/src/pkg/". – Intermernet Aug 18 '14 at 11:14
  • the examples are great, thanks @Intermernet – Jason Xu Aug 19 '14 at 02:40

3 Answers3

32

With the Go threading model, calls to C code, assembler code, or blocking system calls occur in the same thread as the calling Go code, which is managed by the Go runtime scheduler.

The os.LockOSThread() mechanism is mostly useful when Go has to interface with some foreign library (a C library for instance). It guarantees that several successive calls to this library will be done in the same thread.

This is interesting in several situations:

  • a number of graphic libraries (OS X Cocoa, OpenGL, SDL, ...) require all the calls to be done on a specific thread (or the main thread in some cases).

  • some foreign libraries are based on thread local storage (TLS) facilities. They store some context in a data structure attached to the thread. Or some functions of the API provide results whose memory lifecycle is attached to the thread. This concept is used in both Windows and Unix-like systems. A typical example is the errno global variable commonly used in C libraries to store error codes. On systems supporting multi-threading, errno is generally defined as a thread-local variable.

  • more generally, some foreign libraries may use a thread identifier to index/manage internal resources.

Didier Spezia
  • 70,911
  • 12
  • 189
  • 154
  • Great summary!! It also gives me ideas about how to optimise CGO wrapped Clib calls, exactly what I needed. Thx – Jason Xu Aug 19 '14 at 02:38
  • Hmm, some further discussion about optimising Cgo call or not on Gonuts at https://groups.google.com/forum/#!topic/Golang-Nuts/VB_9P29X040 (After knowing more about the internal, my idea above may not help on Cgo performance.) – Jason Xu Aug 19 '14 at 05:03
  • Also very good article describing how the scheduler works. http://morsmachine.dk/go-scheduler – Jason Xu Aug 20 '14 at 02:59
  • Important to add, doing any sort of linux namespace switch (e.g. unsharing a network or process namespace) is also bound to a thread, so if you don't lock the OS thread before you might get part of your code randomly scheduled into a different network/process namespace. – Aurelia Aug 19 '18 at 00:32
  • Some syscalls may depend on os thread. For example, ptrace only works if called from the same thread where it has been inited. – quant2016 Dec 23 '22 at 14:17
6

runtime.LockOsThread it is usually used for calling C code that requires running in the main thread, like in graphics libraries.

Go Wiki page about LockOsThread and an example on how to use it.

Google groups discussion about the use of LockOsThread in SDL.

Marc
  • 1,760
  • 14
  • 10
5

As mentioned here, What runtime.LockOSThread does is prevent any other goroutine from running on the same thread.
But note that Go 1.10 (Q1 2018) will change its usage a bit:

Because one common use of LockOSThread and UnlockOSThread is to allow Go code to reliably modify thread-local state (for example, Linux or Plan 9 name spaces), the runtime now treats locked threads as unsuitable for reuse or for creating new threads.

The behavior of nested calls to LockOSThread and UnlockOSThread has changed. These functions control whether a goroutine is locked to a specific operating system thread, so that the goroutine only runs on that thread, and the thread only runs that goroutine.

Previously, calling LockOSThread more than once in a row was equivalent to calling it once, and a single UnlockOSThread always unlocked the thread.

Now, the calls nest: if LockOSThread is called multiple times, UnlockOSThread must be called the same number of times in order to unlock the thread.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250