Loop to check condition in concurrent program - go

I'm reading a book about concurrency in Go (I'm learning it now) and I found this code:
c := sync.NewCond(&sync.Mutex{})
queue := make([]interface{}, 0, 10)
removeFromQueue := func(delay time.Duration) {
time.Sleep(delay)
c.L.Lock()
queue = queue[1:]
fmt.Println("Removed from queue")
c.L.Unlock() c.Signal()
}
for i := 0; i < 10; i++ {
c.L.Lock()
// Why this loop?
for len(queue) == 2 {
c.Wait()
}
fmt.Println("Adding to queue")
queue = append(queue, struct{}{})
go removeFromQueue(1*time.Second)
c.L.Unlock()
}
The problem is that I don't understand why the author introduces the for loop marked by the comment. As far as I can see, the program would be correct without it, but the author says that the loop is there because Cond will signal that something has happened only, but that doesn't mean that the state has truly changed.
In what case could that be possible?

Without the actual book at hand, and instead just some code snippets that seem out of context, it is hard to say what the author had in mind in particular. But we can guess. There is a general point about condition variables in most languages, including Go: waiting for some condition to be satisfied does require a loop in general. In some specific cases, the loop is not required.
The Go documentation is, I think, clearer about this. In particular, the text description for sync's func (c *Cond) Wait() says:
Wait atomically unlocks c.L and suspends execution of the calling goroutine. After later resuming execution, Wait locks c.L before returning. Unlike in other systems, Wait cannot return unless awoken by Broadcast or Signal.
Because c.L is not locked when Wait first resumes, the caller typically cannot assume that the condition is true when Wait returns. Instead, the caller should Wait in a loop:
c.L.Lock()
for !condition() {
c.Wait()
}
... make use of condition ...
c.L.Unlock()
I added bold emphasis to the phrase that explains the reason for the loop.
Whether you can omit the loop depends on more than one thing:
Under what condition(s) does another goroutine invoke Signal and/or Broadcast?
How many goroutines are running, and what might they be doing in parallel?
As the Go documentation says, there's one case we don't have to worry about in Go, that we might in some other systems. In some systems, the equivalent of Wait is sometimes resumed (via the equivalent of Signal) when Signal (or its equivalent) has not actually been invoked on the condition variable.
The queue example you've quoted is particularly odd because there is only one goroutine—the one running the for loop that counts to ten—that can add entries to the queue. The remaining goroutines only remove entries. So if the queue length is 2, and we pause and wait for a signal that the queue length has changed, the queue length can only have changed to either one or zero: no other goroutine can add to it and only the two goroutines we have created at this point can remove from it. This means that given this particular example, we have one of those cases where the loop is not required after all.
(It's also odd in that queue is given an initial capacity of 10, which is as many items as we'll put in, and then we start waiting when its length is exactly 2, so that we should not reach that capacity anyway. If we were to spin off additional goroutines that might add to the queue, the loop that waits while len(queue) == 2 could indeed be signaled by a removal that drops the count from 2 to 1 but not get a chance to resume until insertion occurs, pushing the count back up to 2. However, depending on the situation, that loop might not be resumed until two other goroutines have each added an entry, pushing the count to 3, for instance. So why repeat the loop when the length is exactly two? If the idea is to preserve queue slots, we should loop while the count is greater than or equal to 2.)
(Besides all this, the initial capacity is not relevant as the queue will be dynamically resized to a large slice if necessary.)

Related

How to get the number of goroutines associated with a WaitGroup?

Let’s say I use a WaitGroup to make the main thread of an application wait until all the goroutines I have launched from said main have completed.
Is there a safe, straightforward, way to assess at any point in time how many goroutines associated with said WaitGroup are still running?
The internal state of the WaitGroup is not exposed, and it won't be: https://github.com/golang/go/issues/7202
I don't think we're likely to make this API more complex. I don't see any way to use
counter and waiters that is not subject to race conditions, other than simply printing
them out. And for that you can maintain your own counts.
You could implement a counter yourself:
type WaitGroupCount struct {
sync.WaitGroup
count int64
}
func (wg *WaitGroupCount) Add(delta int) {
atomic.AddInt64(&wg.count, int64(delta))
wg.WaitGroup.Add(delta)
}
func (wg *WaitGroupCount) Done() {
atomic.AddInt64(&wg.count, -1)
wg.WaitGroup.Done()
}
func (wg *WaitGroupCount) GetCount() int {
return int(atomic.LoadInt64(&wg.count))
}
// Wait() promoted from the embedded field
However, even if the counter access is synchronized, it will become stale immediately after you read it, since other goroutines may go on and call Add or Done irrespective of what you are doing with the count — unless you synchronize the entire operation that depends on the count. But in that case, you might need a more complex data structure altogether.
Is there a safe, straightforward, way to assess at any point in time how many goroutines associated with said waitgroup are still running?
No, there isn't.
Simply because Go (the language) has no notion of "goroutines associated with [a] waitgroup".

The Behaviour Of Goroutines with Channels

The output of the code given bellow and is somewhat confusing, Please help me understand the behaviour of the channels and goroutines and how
does the execution actually takes place.
I have tried to understand the flow of the program but the statement after the "call of goroutine" gets executed, even though the goroutine is called,
later on the statements in goroutines are executed,
on second "call of goroutine" the behaviour is different and the sequence of printing/flow of program changes.
Following is the code:
package main
import "fmt"
func main() {
fmt.Println("1")
done := make(chan string)
go test(done)
fmt.Println("7")
fmt.Println(<-done)
fmt.Println("8")
fmt.Println(<-done)
fmt.Println("9")
fmt.Println(<-done)
}
func test(done chan string) {
fmt.Println("2")
done <- "3"
done <- "10"
fmt.Println("4")
done <- "5"
fmt.Println("6")
}
The result of the above code:
1
7
2
3
8
10
9
4
6
5
Please help me understand why and how this result comes out.
Concept 1: Channels
Visualize a channel as a tube where data goes in one end and out the other. The first data in is the first data that comes out the other side. There are buffered channels and non-buffered channels but for your example you only need to understand the default channel, which is unbuffered. Unbuffered channels only allow one value in the channel at a time.
Writing to an Unbuffered Channel
Code that looks like this writes data into one end of the channel.
ch <- value
Now, this code actually waits to be done executing until something reads the value out of the channel. An unbuffered channel only allows for one value at a time to be within it, and doesn't continue executing until it is read. We'll see later how this affects the ordering of how your code is executed.
Reading from an Unbuffered Channel
To read from an unbuffered channel (visualize taking a value out of the channel), the code to do this looks like
[value :=] <-ch
when you read code documentation [things in] square brackets indicate that what's within them is optional. Above, without the [value :=] you'll just take a value out of the channel and don't use it for anything.
Now when there's a value in the channel, this code has two side effects. One, it reads the value out of a channel in whatever routine we are in now, and proceeds with the value. The other effect it has is to allow the goroutine which put the value into the channel to continue. This is the critical bit that's necessary to understand your example program.
In the event there is NO value in the channel yet, it will wait for a value to be written into the channel before continuing. In other words, the thread blocks until the channel has a value to read.
Concept 2: Goroutines
A goroutine allows your code to continue executing two pieces of code concurrently. This can be used to allow your code to execute faster, or attend to multiple problems at the same time (think of a server where multiple users are loading pages from it at the same time).
Your question arises when you try to figure out the ordering that code is executed when you have multiple routines executing concurrently. This is a good question and others have correctly stated that it depends. When you spawn two goroutines, the ordering of which lines of code are executed is arbitrary.
The code below with a goroutine may print executing a() or end main() first. This is due to the fact that spawning a gorouting means there are two concurrent streams (threads) of execution happening at the same time. In this case, one thread stays in main() and the other starts executing the first line in a(). How the runtime decides to choose which to run first is arbitrary.
func main() {
fmt.Println("start main()")
go a()
fmt.Println("end main()")
}
func a() {
fmt.Println("executing a()")
}
Goroutines + Channels
Now let's use a channel to control the ordering of what get's executed, when.
The only difference now is we create a channel, pass it into the goroutine, and wait for it's value to be written before continuing in main. From earlier, we discussed how the routine reading the value from a channel needs to wait until there's a value in the channel before continuing. Since executing a() is always printed before the channel is written to, we will always wait to read the value put into the channel until executing a() has printed. Since we read from the channel (which happens after the channel is written) before printing end main(), executing a() will always print before end main(). I made this playground so you can run it for yourself.
func main() {
fmt.Println("start main()")
ch := make(chan int)
go a(ch)
<-ch
fmt.Println("end main()")
}
func a(ch chan int) {
fmt.Println("executing a()")
ch <- 0
}
Your Example
I think at this point you could figure out what happens when, and what might happen in a different order. My own first attempt was wrong when I went through it in my head (see edit history). You have to be careful! I'll not give the right answer, upon editing, since I realized this may be a homework assignment.
EDIT: more semantics about <-done
On my first go through, I forgot to mention that fmt.Println(<-done) is conceptually the same as the following.
value := <-done
fmt.Println(value)
This is important because it helps you see that when the main() thread reads from the done channel, it doesn't print it at the same time. These are two separate steps to the runtime.

Cancellation pattern in Golang

Here is a quote from 50 Shades Of Go: Traps, Gotchas and Common mistakes:
You can also use a special cancellation channel to interrupt the
workers.
func First(query string, replicas ...Search) Result {
c := make(chan Result)
done := make(chan struct{})
defer close(done)
searchReplica := func(i int) {
select {
case c <- replicas[i](query):
case <- done:
}
}
for i := range replicas {
go searchReplica(i)
}
return <-c
}
As far as understand, it means that we use channel done to interrupt the workers ahead of time without waiting for full execution (in our case execution of replicas[i](query). Therefore, we can receive a result from the fastest worker ("First Wins Pattern") and then cancel the work in all other workers and save the resources.
On the other hand, according to the specification:
For all the cases in the statement, the channel operands of receive
operations and the channel and right-hand-side expressions of send
statements are evaluated exactly once, in source order, upon entering
the "select" statement.
As far as I understand, it means we cannot interrupt the workers, as in any case, all workers will evaluate function replicas[i]query and only then select case <- done and finish their execution.
Could you please point out at the mistake in my reasoning?
Your reasoning is correct, the wording on the site is not completely clear. What this "construct" achieves is that the goroutines will not be left hanging forever, but once the searches finish, the goroutines will end properly. Nothing more is happening there.
In general, you can't interrupt any goroutine from the outside, the goroutine itself has to support some kind of termination (e.g. shutdown channel, context.Context etc.). See cancel a blocking operation in Go.
So yes, in the example you posted, all searches will be launched, concurrently, result of the fastest one will be returned as it arrives, the rest of the goroutines will continue to run as long as their search is finished.
What happens to the rest? The rest will be discarded (case <- done will be chosen, as an unbuffered channel cannot hold any elements, and there will be no one else receiving more from the channel).
You can verify this in this Go Playground example.

Why is this Go code blocking?

I wrote the following program:
package main
import (
"fmt"
)
func processevents(list chan func()) {
for {
//a := <-list
//a()
}
}
func test() {
fmt.Println("Ho!")
}
func main() {
eventlist := make(chan func(), 100)
go processevents(eventlist)
for {
eventlist <- test
fmt.Println("Hey!")
}
}
Since the channel eventlist is a buffered channel, I think I should get at exactly 100 times the output "Hey!", but it is displayed only once. Where is my mistake?
Update (Go version 1.2+)
As of Go 1.2, the scheduler works on the principle of pre-emptive multitasking.
This means that the problem in the original question (and the solution presented below) are no longer relevant.
From the Go 1.2 release notes
Pre-emption in the scheduler
In prior releases, a goroutine that was looping forever could starve out other goroutines
on the same thread, a serious problem when GOMAXPROCS provided only one user thread.
In Go > 1.2, this is partially addressed: The scheduler is invoked occasionally upon
entry to a function. This means that any loop that includes a (non-inlined) function
call can be pre-empted, allowing other goroutines to run on the same thread.
Short answer
It is not blocking on the writes. It is stuck in the infinite loop of processevents.
This loop never yields to the scheduler, causing all goroutines to lock indefinitely.
If you comment out the call to processevents, you will get results as expected, right until the 100th write. At which point the program panics, because nobody reads from the channel.
Another solution is to put a call to runtime.Gosched() in the loop.
Long answer
With Go1.0.2, Go's scheduler works on the principle of Cooperative multitasking.
This means that it allocates CPU time to the various goroutines running within a given OS thread by having these routines interact with the scheduler in certain conditions.
These 'interactions' occur when certain types of code are executed in a goroutine.
In go's case this involves doing some kind of I/O, syscalls or memory allocation (in certain conditions).
In the case of an empty loop, no such conditions are ever encountered. The scheduler is therefore never allowed to run its scheduling algorithms for as long as that loop is running. This consequently prevents it from allotting CPU time to other goroutines waiting to be run and the result you observed ensues: You effectively created a deadlock that can not be detected or broken out of by the scheduler.
The empty loop is usually never desired in Go and will, in most cases, indicate a bug in the program. If you do need it for whatever reason, you have to manually yield to the scheduler by calling runtime.Gosched() in every iteration.
for {
runtime.Gosched()
}
Setting GOMAXPROCS to a value > 1 was mentioned as a solution. While this will get rid of the immediate problem you observed, it will effectively move the problem to a different OS thread, if the scheduler decides to move the looping goroutine to its own OS thread that is. There is no guarantee of this, unless you call runtime.LockOSThread() at the start of the processevents function. Even then, I would still not rely on this approach to be a good solution. Simply calling runtime.Gosched() in the loop itself, will solve all the issues, regardless of which OS thread the goroutine is running in.
Here is another solution - use range to read from the channel. This code will yield to the scheduler correctly and also terminate properly when the channel is closed.
func processevents(list chan func()) {
for a := range list{
a()
}
}
Good news, since Go 1.2 (december 2013) the original program now works as expected.
You may try it on Playground.
This is explained in the Go 1.2 release notes, section "Pre-emption in the scheduler" :
In prior releases, a goroutine that was looping forever could starve
out other goroutines on the same thread, a serious problem when
GOMAXPROCS provided only one user thread. In Go 1.2, this is partially
addressed: The scheduler is invoked occasionally upon entry to a
function.

Is there a better way to stop an infinite goroutine in Go?

I made a simple clock signal using goroutines:
func clockloop(ch chan byte) {
count := 0
for {
time.Sleep(FRAMELEN)
count++
innerfor:
for count {
select {
case ch <- 1:
count--
default:
break innerfor
}
}
}
}
func MakeClock() chan byte {
clock := make(chan byte)
go clockloop(clock)
return clock
}
I know this clock is imprecise but that is irrelevant. What I want to know is what is the best way to stop this goroutine?
Ideally, I would have liked it to stop as soon as any listeners to the channel go out of scope but I do know how to do that (much like a garbage collector but for goroutines). I have come up with two ways to stop it manually: (1) with a global stop variable that all such goroutines would check every loop and (2) with a stop channel. The disadvantage of each of these is I have to manually stop the goroutines.
A stop channel is a good way to do it. A goroutine must stop itself. There is no way to externally kill one.
For reference there is this thread on Go-Nuts where Ian says essentially this and Russ adds, "Killing individual goroutines is a very unstable thing to do:
it's impossible to know what locks or other resources those
goroutines had that still needed to be cleaned up for the
program to continue running smoothly."

Resources