5

Background:

pthreads follow pre-emptive scheduling, whereas C++ fibers follow cooperative scheduling.

With Pthreads: the current execution path may be interrupted or preempted at any time This means that for threads, data integrity is a big issue because one thread may be stopped in the middle of updating a chunk of data, leaving the integrity of the data in a bad or incomplete state. This also means that the operating system can take advantage of multiple CPUs and CPU cores by running more than one thread at the same time and leaving it up to the developer to guard data access.

Using C,

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

Using threads, application may have Concurrency,

Properties of Concurrency:

1) Multiple actors

2) Shared resource

3) Rules to access(Atomic/Conditional synchronization)


With C++ fibers: the current execution path is only interrupted when the fiber yields execution This means that fibers always start and stop in well-defined places, so data integrity is much less of an issue. Also, because fibers are often managed in the user space, expensive context switches and CPU state changes need not be made, making changing from one fiber to the next extremely efficient. On the other hand, since no two fibers can run at exactly the same time, just using fibers alone will not take advantage of multiple CPUs or multiple CPU cores.

In Win32, a fiber is a sort of user-managed thread. A fiber has its own stack and its own instruction pointer etc., but fibers are not scheduled by the OS: you have to call SwitchToFiber explicitly. Threads, by contrast, are pre-emptively scheduled by the operation system.

So roughly speaking a fiber is a thread that is managed at the application/runti me level rather than being a true OS thread.

Using C,

void __stdcall MyScheduler(void *param){
  ....
}

LPVOID *FiberScheduler = CreateFiber(0, MyScheduler, NULL);

Why C++ fibers?

OS threads give us everything we want, but for a heavy performance penalty: switching between threads involves jumping back and forth from user to kernel mode, possibly even across address space boundaries. These are expensive operations partly because they cause TLB flushes, cache misses and CPU pipelining havoc: that’s also why traps and syscalls can be orders of magnitude slower than regular procedure calls.

In addition, the kernel schedules threads (i.e. assigns their continuation to a CPU core) using a general-purpose scheduling algorithm, which might take into account all kinds of threads, from those serving a single transaction to those playing an entire video.

Fibers, because they are scheduled at the application layer, can use a scheduler that is more appropriate for their use-case. As most fibers are used to serve transactions, they are usually active for very short periods of time and block very often. Their behavior is often to be awakened by IO or another fiber, run a short processing cycle, and then transfer control to another fiber (using a queue or another synchronization mechanism).Such behavior is best served by a scheduler employing an algorithm called “work-stealing”;When fibers behave this way, work-stealing ensures minimal cache misses when switching between fibers.


Fiber does not exploit the power of multiple core, because what OS knows is, single threaded process.

In GO, we invoke goroutines using go keyword

func main(){
  go f() // f runs as new go routine
  f()
}

Question:

1) Is GO routine(f) a fiber that is non-preemptively scheduled by GO runtime, in user space?

2) If yes, Does Concurrency situation arise in GO environment?

3) Does GO support api for OS level thread?

7
  • If OS level thread runs on behalf of goroutine, Is it not premptive scheduling done by OS scheduler? What goroutines want is non-premptive scheduling? Commented Jan 31, 2017 at 20:46
  • A fiber in other contexts is called a coroutine. Commented Feb 3, 2017 at 7:00
  • @AkshatMahajan Am not sure about scheduling of Coroutines in Python vs scheduling of fibers in C++ Commented Mar 25, 2019 at 15:38
  • The term "coroutine" exists outside Python and has a rigorous academic definition: en.wikipedia.org/wiki/Coroutine Commented Mar 25, 2019 at 17:40
  • @AkshatMahajan i think Python co-routines are the same, that is mentioned in wiki Commented Mar 25, 2019 at 17:58

2 Answers 2

3

Question #1: Not really

Goroutines are a bit weird. They are somewhat similar to fibers, but also somewhat similar to threads.

  • They might be preempted.
  • They might be concurrent.
  • They might share resources.
  • They often block on a queue (channel).
  • They have their own stacks.
  • They are not directly scheduled by the OS, but by the golang runtime.

The golang runtime usually starts up to GOMAXPROCS threads by default and schedules your goroutines among them. On any given thread, a goroutine will run until completion or until it blocks on a channel.

That means you can think of goroutines as fibers shared among threads.

This means that you can think of goroutines that don't access global state like you would think of fibers. But for goroutines that do access global state, you need to treat of them like threads.

Question #2: Yes

You need to be mindful when accessing global state!

However, the default communication mechanism, channels, synchronizes access to shared resources, which eases concurrent programming in Go by a lot.

Question #3: Not in the standard library

If you really want to, you could start threads by writing a library in C for Go that gives you access to the underlying OS thread functions (like pthread_create).

However, I strongly doubt you could use goroutines and channels on threads created in this way, as the golang runtime scheduler has no knowledge of them.

This might also cause problems with calls to other libraries (like the standard library!) that assume access to goroutines and channels.

In conclusion, I don't think directly creating and managing threads in Go is a good idea.

12
  • At OS level, only single threaded GO executable is visible to OS? Commented Jan 31, 2017 at 12:29
  • @overexchange: Sorry, but I don't really get your question. A Go executable might start up to GOMAXPROCS OS threads. There might be multiple Go executables (processes) running at the same time.
    – hoffmale
    Commented Jan 31, 2017 at 12:36
  • 1
    Gouroutines cannot be preempted! Commented Jan 31, 2017 at 13:31
  • @GrzegorzŻur: They cannot be preempted by the golang runtime scheduler - but the OS preempting a thread is a different story, Since goroutines can run on different OS threads, the OS scheduler can (of course!) preempt those threads (which might be perceived by goroutines on other threads).
    – hoffmale
    Commented Jan 31, 2017 at 13:41
  • 1
    @hoffmale When you say: On any given thread, a goroutine will run until completion or until it blocks on a channel. I think you are talking about user-land threads. Is that correct? Commented Mar 25, 2019 at 16:59
6

Golang Goroutines are a compiler facility. Conceptually Goroutines and fibers are cooperative multitasking methods with respect to the Environment. Fibers are a OS level concept, whereas goroutine is a compiler level concept.

Goroutines may match a specification of Fibre (there seem to be many) but not necessarily fibre in the strictest sense. In fact a goroutines may be spread across multiple threads as decided by the scheduler.

  1. For the provided explanation of fibre. Yeah, Goroutines could be called as an implementation of the fibre spec put by you.

  2. You should ideally be thinking in terms of CSPs rather than concurrency.

Communicating Sequential Processes (CSP) is go's model of concurrency and Goroutines enable that. Isolating away the goroutine component and thinking of concurrency is a bit off from golangs perspective.

You are encouraged to use Channels to maintain flow of data and not rely on any other mechanism for syncing (as pike says, do not communicate by sharing, share by communicating). Though you can still use mutexes if you desire, but, you still cannot create threads on your own.

In fact, go's approach to concurrency is closer to erlang than other traditional languages and their implementations.

  1. For the same reason as above. Go doesn't allow you to directly create threads (you can spawn multiple processes, though). You are encouraged to use only Goroutines with channels to prevent confusions from using multiple multitasking approaches.

Go uses the same number of OS threads as set by environment variable GOMAXPROCS (which as of GO1.5 is set to the CPU core count).

Here is a great discussion on it

7
  • For your point: goroutines may be spread across multiple threads as decided by the scheduler.. How do you create thread using GO? Commented Jan 31, 2017 at 7:06
  • The abbreviation 'CSP' can mean multiple things. Can you indicate in your answer how it should be interpreted here? Commented Jan 31, 2017 at 7:11
  • @overexchange Go doesn't allow you to create threads. But internally it does use OS threads. AFAIK.
    – onkkno
    Commented Jan 31, 2017 at 8:12
  • @BartvanIngenSchenau Here CSPs mean Communicating Sequential Processes.I'll edit my answer too.Thanks
    – onkkno
    Commented Jan 31, 2017 at 8:13
  • 1
    As of Go1.5 Go automatically can detect and use all your CPU cores as needed depending on the Goroutines you spawn. I meant YOU don't have to do the distribution among CPU cores part. but golang WILL and CAN use all your CPU cores. There's even an environment variable (GOMAXPROCS) that allow you to tune the maximum processes for your Program.(Sometimes go programs can slow down with a high GOMAXPROCS value so you;ve to tune accordingly. Large number of spawned processes doesn't necessarily directly result in faster execution. It depends on the code.)
    – onkkno
    Commented Jan 31, 2017 at 9:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.