Why is the main queue misbehaving inside dispatchMain()? - macos

The following program:
import Foundation
DispatchQueue.main.async {
print("(1) on main thread: \(Thread.isMainThread)")
DispatchQueue.main.async {
// executed on a different thread!
print("(2) on main thread: \(Thread.isMainThread)")
}
}
dispatchMain()
prints:
(1) on main thread: true
(2) on main thread: false
This is odd because the main dispatch queue is supposed to be a serial queue that executes tasks only on the application's main thread. Replacing dispatchMain() with CFRunLoopRun() yields the expected result, with both tasks running on the main thread. So what is the intended use of dispatchMain(), and how is it affecting the code above?

Related

Coroutine launched without specifying a dispatcher is not getting cancelled

I created a coroutine with just one computation loop with the exit condition of isActive. It cancels correctly when I specify the default dispatcher, but does not cancel when no dispatcher is defined.
//This example cancels as expected
fun main() = runBlocking {
val job = launch(Dispatchers.Default) {
println("Start job 1")
var i =0
while (isActive){
print(i++)
print(i--)
}
println("End job 1")
}
job.cancelAndJoin()
}
However, the below example does not cancel and keeps executing the loop.
fun main() = runBlocking {
val job = launch {
println("Start job 2")
var i =0
while (isActive){
print(i++)
print(i--)
}
println("End job 2")
}
job.cancelAndJoin()
}
Why is the second example behaving differently?
With runBlocking, if you don't specify a dispatcher, coroutines will be dispatched directly on the current thread, using an event loop. Because there's only a single thread in use, the coroutines can't run in parallel. Once the loop is started, it runs continuously, occupying the thread. That means that the call to cancelAndJoin can never be reached, even though it's in a separate coroutine, because there's no thread available to continue running that coroutine.
When you use the default dispatcher, you're introducing more threads. The default dispatcher has a pool of threads, meaning that coroutines can run in parallel. That means that the code can continue and reach the call to cancelAndJoin even when the loop is still running.

Wait for a non child Process to end

Hi I am working on a simple code that will monitor a process and restart the process in case the process crashes. I have written a small sample code.
This is my external process
package main
import (
"fmt"
"time"
)
func main() {
for {
time.Sleep(1000 * time.Millisecond)
fmt.Println("hello")
}
}
This is the code that monitors it.
package main
import (
"fmt"
"os"
)
func main() {
p, e := os.FindProcess(<processid>)
fmt.Println(e)
fmt.Println(p.Wait())
fmt.Println("done")
}
The challenge here is that since the first process is not a child process of the second one, it does not wait and directly exits.
Please let me know if anyone has any ideas around this.
Thanks.
Monitoring process exits because p.Wait() does not block.
From the docs:
On most operating systems, the Process must be a child of the current
process or an error will be returned.
You can perhaps poll the process pool to check if the process still exists.

How to implement a PHP function `die()` (or `exit()`) in Go?

In PHP, die() is used to stop running the script for preventing the unexpected behaviour. In Go, what is the idiomatic way to die a handle function? panic() or return?
You should use os.Exit.
Exit causes the current program to exit with the given status code.
Conventionally, code zero indicates success, non-zero an error. The
program terminates immediately; deferred functions are not run.
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Start")
os.Exit(1)
fmt.Println("End")
}
Even, you can use panic, it's also stop normal execution but throw Error when execution stop.
The panic built-in function stops normal execution of the current
goroutine. When a function F calls panic, normal execution of F stops
immediately. Any functions whose execution was deferred by F are run
in the usual way, and then F returns to its caller. To the caller G,
the invocation of F then behaves like a call to panic, terminating G's
execution and running any deferred functions. This continues until all
functions in the executing goroutine have stopped, in reverse order.
At that point, the program is terminated and the error condition is
reported, including the value of the argument to panic. This
termination sequence is called panicking and can be controlled by the
built-in function recover.
package main
import "fmt"
func main() {
fmt.Println("Start")
panic("exit")
fmt.Println("End")
}
If you don't want to print a stack trace after exiting the program, you can use os.Exit. Also you are able to set a specific exit code with os.Exit.
Example (https://play.golang.org/p/XhDkKMhtpm):
package main
import (
"fmt"
"os"
)
func foo() {
fmt.Println("bim")
os.Exit(1)
fmt.Println("baz")
}
func main() {
foo()
foo()
}
Also be aware, that os.Exit immediately stops the program and doesn't run any deferred functions, while panic() does. See https://play.golang.org/p/KjGFZzTrJ7 and https://play.golang.org/p/Q4iciT35kP.
You can use panic in HTTP handler. Server will handle it. See Handler.
If ServeHTTP panics, the server (the caller of ServeHTTP) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.
Function panic is reserved for the situation when program just cannot continue. Inability to serve just one request is not the same as inability to continue to work, so I would log the error, set a correct HTTP status and use return. See Effective Go.
The usual way to report an error to a caller is to return an error as an extra return value. The canonical Read method is a well-known instance; it returns a byte count and an error. But what if the error is unrecoverable? Sometimes the program simply cannot continue.
The idiomatic way to break a function in Go is to use panic(). This is the defacto way to stop the execution of an event on runtime. If you want to recover the panic you can use the built in recover() function.
Panic explanation:
Panic is a built-in function that stops the ordinary flow of control
and begins panicking. When the function F calls panic, execution of F
stops, any deferred functions in F are executed normally, and then F
returns to its caller.
https://blog.golang.org/defer-panic-and-recover
Recover explanation:
Recover is a built-in function that regains control of a panicking
goroutine. Recover is only useful inside deferred functions. During
normal execution, a call to recover will return nil and have no other
effect. If the current goroutine is panicking, a call to recover will
capture the value given to panic and resume normal execution.
https://blog.golang.org/defer-panic-and-recover
And here is a simple example:
package main
import "fmt"
func badCall() {
panic("Bad call happend!")
}
func test() {
defer func() {
if err := recover(); err != nil {
fmt.Printf("Panicking %s\n\r", err)
}
}()
badCall()
fmt.Println("This is never executed!!")
}
func main() {
fmt.Println("Start testing")
test()
fmt.Println("End testing")
}

Main thread never yields to goroutine

edit * -- uncomment the two runtime lines and change Tick() to Sleep() and it works as expected, printing one number every second. Leaving code as is so answer/comments make sense.
go version go1.4.2 darwin/amd64
When I run the following, I never see anything printed from go Counter().
package main
import (
"fmt"
"time"
//"runtime"
)
var count int64 = 0
func main() {
//runtime.GOMAXPROCS(2)
fmt.Println("main")
go Counter()
fmt.Println("after Counter()")
for {
count++
}
}
func Counter() {
fmt.Println("In Counter()")
for {
fmt.Println(count)
time.Tick(time.Second)
}
}
> go run a.go
main
after Counter()
If I uncomment the runtime stuff, I will get some strange results like the following all printed at once (not a second apart):
> go run a.go
main
after Counter()
In Counter()
10062
36380
37351
38036
38643
39285
39859
40395
40904
43114
What I expect is that go Counter() will print whatever count is at every second while it is incremented continuously by the main thread. I'm not so much looking for different code to get the same thing done. My question is more about what is going on and where am I wrong in my expectations? The second results in particular don't make any sense, being printed all at once. They should never be printed closer than a second apart as far as I can tell, right?
There is nothing in your tight for loop that lets the Go scheduler run.
The schedule considers other goroutines whenever one blocks or on some (which? all?) function calls.
Since you do neither the easiest solution is to add a call to runtime.Gosched. E.g.:
for {
count++
if count % someNum == 0 {
runtime.Gosched()
}
}
Also note that writing and reading the same variable from different goroutines without locking or synchronization is a data race and there are no benign data races, your program could do anything when reading a value as it's being written. (And synchronization would also let the Go scheduler run.)
For a simple counter you can avoid locks by using atomic.AddInt64(&var, 1) and atomic.LoadInt64(&var).
Further note (as pointed out by #tomasz and completely missed by me), time.Tick doesn't delay anything, you may have wanted time.Sleep or for range time.Tick(…).

Golang: goroutine infinite-loop

When an fmt.Print() line is removed from the code below, code runs infinitely. Why?
package main
import "fmt"
import "time"
import "sync/atomic"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
fmt.Print()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
The Go By Example article includes:
// Allow other goroutines to proceed.
runtime.Gosched()
The fmt.Print() plays a similar role, and allows the main() to have a chance to proceed.
A export GOMAXPROCS=2 might help the program to finish even in the case of an infinite loop, as explained in "golang: goroute with select doesn't stop unless I added a fmt.Print()".
fmt.Print() explicitly passes control to some syscall stuff
Yes, go1.2+ has 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.
Notice the emphasis (that I put): it is possible that in your example the for loop atomic.AddUint64(&ops, 1) is inlined. No pre-emption there.
Update 2017: Go 1.10 will get rid of GOMAXPROCS.

Resources