Wait for a non child Process to end - go

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.

Related

Is the main function run a goroutine?

Is the main() function a goroutine? For example, I've seen a crash stack trace like the below, which makes me ask:
goroutine 1 [running]: main.binarySearch(0x0, 0x61, 0x43,
0xc420043e70, 0x19, 0x19, 0x10)
/home/---/go/src/github.com/----/sumnum.go:22 +0x80 main.main()
/home/---/go/src/github.com/---/sumnum.go:13 +0xc1 exit status 2
Is the main function a goroutine?
No.
The main function is a function.
In contrast,
A goroutine is a lightweight thread of execution. (source).
So goroutines execute functions, but goroutines are not functions, and there is not a 1-to-1 relationship between goroutines and functions.
However...
The main() function is executed in the first (and at startup, only) goroutine, goroutine #1.
But as soon as that function calls another function, then the main goroutine is no longer executing the main function, and is instead executing some other function.
So it's clear that a goroutine and a function are entirely different entities.
Do not conflate goroutines with functions!!
Functions and goroutines are entirely different concepts. And thinking of them as the same thing will lead to countless confusion and problems.
Yes, the main function runs as a goroutine (the main one).
According to https://tour.golang.org/concurrency/1
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running f(x, y, z) The evaluation of f, x, y, and z happens in the current goroutine and the execution of f happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory must be synchronized. The sync package provides useful primitives, although you won't need them much in Go as there are other primitives.
So according to this official document the main is the current goroutine.
To be precise (literally) we could address the main as the current goroutine, so simply speaking it is a goroutine. (Note: Literally speaking the main() is a function which could run as a goroutine.)
Now let's count the number of goroutines using runtime.NumGoroutine():
As an example let's run 3 goroutines. Try it online:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 3
time.Sleep(100 * time.Millisecond)
}
func init() {
go main()
go main()
}
Here the current goroutine runs the new goroutine, so here we have more than one goroutine, which executes main() again. Try it online:
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 1 2 3 4
if atomic.LoadInt32(&i) <= 0 {
return
}
atomic.AddInt32(&i, -1)
go main()
time.Sleep(100 * time.Millisecond)
}
var i int32 = 3
Output:
1
2
3
4
Here we have one main goroutine plus 3 user called main goroutines, so total number of goroutines are 4 here.
Let's calculate factorial using main() (one goroutine - no synchronization needed). Try it online:
package main
import "fmt"
func main() {
if f <= 0 {
fmt.Println(acc)
return
}
acc *= f
f--
main()
}
var f = 5
var acc = 1
Output:
120
Note: The codes above are just for clearly showing my viewpoints and is not good for production use (Using global variables should not be the first choice).
Yes. Main func can spawn other goroutines, but "main" itself is one groutine.
package main
import (
"fmt"
"runtime"
)
func main() {
// Goroutine num includes main processing
fmt.Println(runtime.NumGoroutine()) // 1
// Spawn two goroutines
go func() {}()
go func() {}()
// Total three goroutines run
fmt.Println(runtime.NumGoroutine()) // 3
}

Querying ProcessState

I have a simple program and runs an exe and checks the Exited value afterwards, but it is giving me an "panic: runtime error: invalid memory address or nil pointer dereference" error, any idea why?
package main
import (
"fmt"
"os/exec"
"time"
)
func main() {
prog:= exec.Command("path\to\exe")
prog.Dir = "path\to"
go prog.Run()
fmt.Println(prog.ProcessState.Exited())
time.Sleep(500 * time.Second)
}
The documentation says:
ProcessState contains information about an exited process available after a call to Wait or Run.
The main goroutine accesses the ProcessState field before the field is set to a non-nil value by the call to Run() in the goroutine. The call to Exited() panics as a result.
A simple fix is to call Run() from the main goroutine.

Creating slice byte goroutine hangs

I have an upload program that I am working on and I am running into an issue. I have n go routines that handle uploading the parts to a big file. Essentially it will split the file into 100MB chunks and upload them concurrently depending on the amount of concurrent processes you specify in the config.
The issue I'm having is when I create a buffer to read the file and upload the make([]byte, 100000000) hangs... but only if it's in a go routine. (I'm using 100000000 to simplify the upload calculations)
Here is an example.
This works: https://play.golang.org/p/tkn8JVir9S
package main
import (
"fmt"
)
func main() {
buffer := make([]byte, 100000000)
fmt.Println(len(buffer))
}
This doesn't: https://play.golang.org/p/H8626OLpqQ
package
main
import (
"fmt"
)
func main() {
go createBuffer()
for {
}
}
func createBuffer() {
buffer := make([]byte, 100000000)
fmt.Println(len(buffer))
}
It just hangs... I'm not sure if there is a memory constraint for a go routine? I tried to research and see what I could find but nothing. Any thoughts would be appreciated.
EDIT: Thanks everyone for the feedback. I will say I didn't explain the real issue very well and will try to provide more of a holistic view next time. I ended up using a channel to block to keep my goroutines ready for new files to process. This is for a DR backup uploading to a 3rd party all that requires large files to be split into 100mb chunks. I guess I should have been more clear as to the nature of my program.
This program hangs because there is an infinite loop in your code. Try running the code just like this to prove it to yourself. The goroutine is not what is causing the hanging.
func main() {
for {
}
}
If you just want to see fmt.Println(..) print, then I'd recommend having a time.Sleep call or similar.
If you would like to wait for a bunch of goroutines to complete, then I'd recommend this excellent answer to that exact question.
Package runtime
import "runtime"
func Gosched
func Gosched()
Gosched yields the processor, allowing other goroutines to run. It
does not suspend the current goroutine, so execution resumes
automatically.
When you do something strange (for {} and 100MB), you get strange results. Do something reasonable. For example,
package main
import (
"fmt"
"runtime"
)
func main() {
go createBuffer()
for {
runtime.Gosched()
}
}
func createBuffer() {
buffer := make([]byte, 100000000)
fmt.Println(len(buffer))
}
Output:
100000000
^Csignal: interrupt

why the "infinite" for loop is not processed?

I need to wait until x.Addr is being updated but it seems the for loop is not run. I suspect this is due the go scheduler and I'm wondering why it works this way or if there is any way I can fix it(without channels).
package main
import "fmt"
import "time"
type T struct {
Addr *string
}
func main() {
x := &T{}
go update(x)
for x.Addr == nil {
if x.Addr != nil {
break
}
}
fmt.Println("Hello, playground")
}
func update(x *T) {
time.Sleep(2 * time.Second)
y := ""
x.Addr = &y
}
There are two (three) problems with your code.
First, you are right that there is no point in the loop at which you give control to the scheduler and such it can't execute the update goroutine. To fix this you can set GOMAXPROCS to something bigger than one and then multiple goroutines can run in parallel.
(However, as it is this won't help as you pass x by value to the update function which means that the main goroutine will never see the update on x. To fix this problem you have to pass x by pointer. Now obsolete as OP fixed the code.)
Finally, note that you have a data race on Addr as you are not using atomic loads and stores.

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