what happened when use '-race' flag in go build - go

I am confusing for following code, what's the difference between go run with go run -race, Does the -race will change the program behavior?
// test.go
package main
import "fmt"
func main() {
c := make(chan string)
go func() {
for i := 0; i < 2; i++ {
c <- "hello there"
}
}()
for msg := range c {
fmt.Println(msg)
}
}
when go run test.go, result is :
hello there
hello there
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/donghui6/go/src/jd.com/iaas-sre/test/test.go:14 +0xf4
exit status 2
when go run -race test.go, program will hang as following:
hello there
hello there
so, who can tell me what happened when use -race flag

what happen[s] when use '-race' flag in go build
Then the program is built with the so called "race detector" enabled. Dataraces are a programming error and any program with a datarace is invalid and its behaviour is undefined. You must never write code with data races.
A data race is when two or more goroutines read and write to the same memory without proper synchronisation. Data races happen but are a major fault of the programmer.
The race detector detects unsynchronised read/writes to the same memory and reports them as a failure (which it is). Note that if the race detector detects a data race your code is buggy even if it runs "properly" without -race.
The race detector is not on always because detecting data races slows down execution drastically.

Related

Can not running a Go app (using os library) with cron job

I had a problem when I tried run a Go app with cron job. It's seem that every func of os library can not execute in cron job. Here is my code. I've searched for a lot of time but haven't got any solotion yet.
Here is my code.
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
out, err := exec.Command("ls").Output()
file, _ := os.Create("test.txt")
_, err1 := file.Write([]byte(string(out) + "\n"))
if err == nil && err1 == nil {
fmt.Println("test")
}
fmt.Println(string(out))
}
Here is my cron job
* * * * * go run /root/code/main.go
Please help me fix this problem or any recommend to run a go app with cron job.
By default, cron jobs are run with the root user, and probably there is no go binary in your root user's path.
To check this, you can run.
# crontab -e
* * * * * whoami >> /tmp/debug.txt && where go && echo OK >> /tmp/debug.txt || echo ERROR >> /tmp/debug.txt
Which will show you user info and "Can I find go binary" information.
You can change the user who runs the cronjob
Better Way
As others said, it's not a good idea to run Go code with go run. Each time compiler needs to compile the code and run it.
If you run go build and run the produced executable, it'll simplify your workflow. Also, by default, go binaries are single binaries that contain all dependencies, which simplifies lots of things. You can just ./executable-name anywhere

How to print gc traces by embedding gctrace env with go binary?

I have a simple program that prints hello world. To emit gc trace information am using following command by directly running the main.go file
$ GODEBUG=gctrace=1 go run main.go
gc 1 #0.011s 1%: 0.020+1.3+0.056 ms clock, 0.24+0.62/0.38/1.6+0.67 ms cpu, 4->4->0 MB, 5 MB goal, 12 P
Hello Playground
gc 2 #0.021s 0%: 0.004+0.55+0.006 ms clock, 0.052+0.12/0.36/0.49+0.079 ms cpu, 4->4->0 MB, 5 MB goal, 12 P
Question
Is there a way to build the binary and yet print the gctraces while running the binary directly and without explicitly passing the GODEBUG=gctrace=1 to the binary?
(OR)
How to build binary with GODEBUG=gctrace=1 without explicitly mentioning at runtime ?
$ go build -O main // (builds binary main)
$ ./main // doesn't print gc trace information
Hello Playground
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
}

Why subprocess "sleep 10" does not terminate?

I need to test if a process terminates and all I have is its pid number. To do so I test if the pseudo file "/proc/<pid>" exist.
Writing a test for this function, I noticed that the process doesn’t terminate as expected.
For the test, I run "sleep 10" as sub-process which should run for 10 seconds. After starting this process, I poll for the disappearance of the pseudo file "/proc/<pid>". That pseudo file never disappear and the termination of the sub-process is not detected.
Testing the code of golang playground reproduces the problem: https://play.golang.org/p/fb4CbXkIjh3.
I checked that the process is created, and that the pid is correct. While checking the process is seen that it turns into <defunct>. It isn’t thus removed.
The questions are the following:
why doesn’t the sub-process terminate ?
how can I change the code to make it terminate ?
package main
import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
"time"
)
func main() {
fmt.Println("Hello, playground")
cmd := exec.Command("sleep", "10")
if err := cmd.Start(); err != nil {
log.Fatal("unexpected error:", err)
}
pidStr := strconv.Itoa(cmd.Process.Pid)
log.Println("sleep pid:", pidStr)
for {
if _, err := os.Stat("/proc/" + pidStr); os.IsNotExist(err) {
log.Println("detect termination of /proc/" + pidStr)
return
}
log.Println("pgm /proc/" + pidStr + " is running")
time.Sleep(3 * time.Second)
}
}
At the OS level, in any POSIX-compatible OS (Unix, Linux, Darwin, etc), a process that has completed, but not yet been collected by its superior, is in "defunct" or "zombie" state. It still exists, but cannot be killed: it is already dead. It exists precisely so that its superior—the process that can call the OS level wait system call—can call the OS level wait system call and see that the process is now dead.
Once its superior has waited for it, the process is truly removed: there is no longer a zombie process hogging that process ID. If you have a /proc file system, this is when the process vanishes from /proc.
In Go, calling cmd.Wait() invokes the OS-level wait call, so that is the way to do this. If you would like to collect the result of this cmd.Wait(), a good way to do that is to send it through a channel.
(If you want to spawn a very long running process and not wait for it, you can disown it, so that you are no longer its superior. The details on doing this correctly are full of OS-specific doodads, such as discarding control ttys, setting sessions, using procctl or prctl, and so on.)

Should pcall catch PANIC errors (ESP32 NodeMCU)?

I've such code:
print("AAAAAA")
local status, jobj = pcall(json.decode(docTxt))
print("BBBBBB")
decode method causes PANIC error, an it results in following console output:
AAAAAAA
PANIC: unprotected error in call to Lua API (json.lua:166: 'for' initial value must be a number)
Whole program beaks, BBBBB does not get printed to console.
Is this normal? Is pcall broken ?
I was able to figure it out: it can be configured in watchdog options for firmware compiler. Now I've have such setup, that it reboots on panic.

How to get an exclusive lock on a file in go

How can I get an exclusive read access to a file in go? I have tried documentations from docs but I am still able to open the file in notepad and edit it. I want to deny any other process to have access to read and write while the first process has not closed it explicitly. In .NET I could do something as:
File.Open("a.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.None);
How do I do it in go?
I finally found a go package that can lock a file.
Here is the repo:
https://github.com/juju/fslock
go get -u github.com/juju/fslock
this package does exactly what it says
fslock provides a cross-process mutex based on file locks that works
on windows and *nix platforms. fslock relies on LockFileEx on Windows
and flock on *nix systems. The timeout feature uses overlapped IO on
Windows, but on *nix platforms, timing out requires the use of a
goroutine that will run until the lock is acquired, regardless of
timeout. If you need to avoid this use of goroutines, poll TryLock in
a loop.
To use this package, first, create a new lock for the lockfile
func New(filename string) *Lock
This API will create the lockfile if it already doesn't exist.
Then we can use the lockhandle to lock (or try lock) the file
func (l *Lock) Lock() error
There is also a timeout version of the above function that will try to get the lock of the file until timeout
func (l *Lock) LockWithTimeout(timeout time.Duration) error
Finally, if you are done, release the acquired lock by
func (l *Lock) Unlock() error
Very basic implementation
package main
import (
"time"
"fmt"
"github.com/juju/fslock"
)
func main() {
lock := fslock.New("../lock.txt")
lockErr := lock.TryLock()
if lockErr != nil {
fmt.Println("falied to acquire lock > " + lockErr.Error())
return
}
fmt.Println("got the lock")
time.Sleep(1 * time.Minute)
// release the lock
lock.Unlock()
}

Resources