Resolving conflicts with goroutines? - go

I have a really minor doubt
Suppose there are three func A,B,C
C is being called from both A and B
I am running A and B on different threads , will it result in conflict any time in feature when it calls C within it
for reference i am adding this code
package main
import (
"fmt"
)
func xyz() {
for true {
fmt.Println("Inside xyz")
call("xyz")
}
}
func abc() {
for true {
fmt.Println("Inside abc")
call("abc")
}
}
func call(s string) {
fmt.Println("call from " + s)
}
func main() {
go xyz()
go abc()
var input string
fmt.Scanln(&input)
}
Here A = xyz(), B = abc(), C = call()
will there be any conflict or any runtime error in future while running these two go routines

Whether multiple goroutines are safe to run concurrently or not comes down to whether they share data without synchronization. In this example, both abc and xyz print to stdout using fmt.Println, and call the same routine, call, which prints to stdout using fmt.Println. Since fmt.Println doesn't use synchronization when printing to stdout, the answer is no, this program is not safe.

Related

Same pointer different values, in multi file main package

My project is a login-register web server that consists of multiple files and uses another package in which the Manager struct is defined.
Overview of my files:
my-package/
main.go
handlers.go
...
I have a variable: var M *Manager declared in main.go before definition of main() and it is assigned inside main():
var M *Manager
func main() {
...
M = InitManager(...)
...
}
handleLogin(...) and handleRegister(...) are functions defined in handlers.go that use the M variable:
func handleRegister(...){
...
fmt.Println("M:", M)
M.Log1("logging informations...")
...
}
func handleLogin(...) {
...
fmt.Println("M:", M)
M.GetAccount(login)
...
}
When I go to /loginor /register and the appropriate handle function is triggered it displays: M: <nil>
To find out something more I modified main() as shown below:
var M *Manager
func main() {
...
go func() { // for debugging
for {
fmt.Println("main() goloop1: M:", M)
time.Sleep(time.Second / 2)
}
}()
M = InitManager(...)
go func() { // for debugging
for {
fmt.Println("main() goloop2: M:", M)
time.Sleep(time.Second / 2)
}
}()
...
}
and the output:
main() goloop2: M: &{...data as expected...}
main() goloop1: M: <nil>
main() goloop2: M: &{...data as expected...}
main() goloop1: M: <nil>
...
My question are:
How do pointers work then if one pointer gives out two values?
How to fix my issue and properly plan code (if that was the cause) to avoid this in future?
Per the Go Memory Model, the provided code writes and reads M without proper synchronization, which is a data race and leads to undefined behavior (see icza's comment).
The compiler "assumes" that the code is properly synchronized (this is the responsibility of the developer) and so it is "allowed" to assume that M is never modified inside the infinite loops, so it may use a copy in a given register or stack memory location over and over, leading to the surprising output.
You may use a sync.Mutex to protect every access to the global *Manager variable M, as in this modified code.
Also beware of variable shadowing! It is possible to write M := f() instead of M = f(), resulting in an unrelated local variable, not affecting the global variable.
My solution:
I have added init.go:
my-package/
main.go
handlers.go
...
init.go
I moved global variables like M and CONFIG_MAP into the init.go file:
package main
import ...
var CONFIG_MAP = LoadConfig()
var M *asrv.Manager = InitManager()
func LoadConfig() map[string]string {
// return map from 'conf.json' file
}
func InitManager() *asrv.Manager {
// return Manager configured with CONFIG_MAP
// other functions also use CONFIG_MAP that is the reason why it is global
}
func init() {
LoadTemplatesFiles() // load templates and assign value
// to a variable declared in templates.go
}
This way handler functions (handleLoginGet etc.) in handlers.go could properly read M.
This fix just made my program work and I still don't know what is the proper way of handling this type of situation, that is why I added more info under EDIT in my question.

Go goroutine test failing Expected number of calls

I'm new to Go here. I am trying to test the function call inside my Go routine but it fails with the error message
Expected number of calls (8) does not match the actual number of calls
(0).
My test code goes like:
package executor
import (
"testing"
"sync"
"github.com/stretchr/testify/mock"
)
type MockExecutor struct {
mock.Mock
wg sync.WaitGroup
}
func (m *MockExecutor) Execute() {
defer m.wg.Done()
}
func TestScheduleWorksAsExpected(t *testing.T) {
scheduler := GetScheduler()
executor := &MockExecutor{}
scheduler.AddExecutor(executor)
// Mock exptectations
executor.On("Execute").Return()
// Function Call
executor.wg.Add(8)
scheduler.Schedule(2, 1, 4)
executor.wg.Wait()
executor.AssertNumberOfCalls(t, "Execute", 8)
}
and my application code is:
package executor
import (
"sync"
"time"
)
type Scheduler interface {
Schedule(repeatRuns uint16, coolDown uint8, parallelRuns uint64)
AddExecutor(executor Executor)
}
type RepeatScheduler struct {
executor Executor
waitGroup sync.WaitGroup
}
func GetScheduler() Scheduler {
return &RepeatScheduler{}
}
func (r *RepeatScheduler) singleRun() {
defer r.waitGroup.Done()
r.executor.Execute()
}
func (r *RepeatScheduler) AddExecutor(executor Executor) {
r.executor = executor
}
func (r *RepeatScheduler) repeatRuns(parallelRuns uint64) {
for count := 0; count < int(parallelRuns); count += 1 {
r.waitGroup.Add(1)
go r.singleRun()
}
r.waitGroup.Wait()
}
func (r *RepeatScheduler) Schedule(repeatRuns uint16, coolDown uint8, parallelRuns uint64) {
for repeats := 0; repeats < int(repeatRuns); repeats += 1 {
r.repeatRuns(parallelRuns)
time.Sleep(time.Duration(coolDown))
}
}
Could you point out to me what I could be doing wrong here? I'm using Go 1.16.3. When I debug my code, I can see the Execute() function being called but testify is not able to register the function call
You need to call Called() so that mock.Mock records the fact that Execute() has been called. As you are not worried about arguments or return values the following should resolve your issue:
func (m *MockExecutor) Execute() {
defer m.wg.Done()
m.Called()
}
However I note that the way your test is currently written this test may not accomplish what you want. This is because:
you are calling executor.wg.Wait() (which will wait until the function has been called the expected number of times) before calling executor.AssertNumberOfCalls so your test will never complete if Execute() is not called at least the expected number of times (wg.Wait() will block forever).
After m.Called() has been called the expected number of times there is a race condition (if executor is still be running there is a race between executor.AssertNumberOfCalls and the next m.Called()). If wg.Done() does get called an extra time you will get a panic (which I guess you could consider a fail!) but I'd probably simplify the test a bit:
scheduler.Schedule(2, 1, 4)
time.Sleep(time.Millisecond) // Wait long enough that all executions are guaranteed to have completed (should be quick as Schedule waits for go routines to end)
executor.AssertNumberOfCalls(t, "Execute", 8)

Calling a variable from another function in go

I know that variables are pass by value in go. However, I want to call a variable that in inside a func outside this function. Let me give you an example:
package main
import (
"fmt"
)
func Smile(){
A := 5
}
func main() {
fmt.Println(A)
}
This gives me undefine A.
what is the best way to pass A ? Should I use a pointer? How do I do that?
It's not possible to print the value of the A variable declared in the Smile() function from main().
And the main reason for that is that the variable A only exists if code execution enters the Smile() function, more precisely reaches the A variable declaration. In your example this never happens.
And even if in some other example this happens (e.g. Smile() is called), an application may have multiple goroutines, and multiple of them may be executing Smile() at the same time, resulting in the app having multiple A variables, independent from each other. In this situation, which would A in main() refer to?
Go is lexically scoped using blocks. This means the variable A declared inside Smile() is only accessible from Smile(), the main() function cannot refer to it. If you need such "sharing", you must define A outside of Smile(). If both Smile() and main() needs to access it, you have to make it either a global variable, or you have to pass it to the functions that need it.
Making it a global variable, this is how it could look like:
var a int
func smile() {
a = 5
fmt.Println("a in smile():", a)
}
func main() {
smile()
fmt.Println("a in main():", a)
}
This outputs (try it on the Go Playground):
a in smile(): 5
a in main(): 5
Declaring it local in main() and passing it to smile(), this is how it could look like:
func smile(a int) {
fmt.Println("a in smile():", a)
}
func main() {
a := 5
fmt.Println("a in main():", a)
smile(a)
}
Output (try it on the Go Playground):
a in main(): 5
a in smile(): 5
The best way is, https://godoc.org/golang.org/x/tools/go/pointer
Pointers
Ex:
func getCar() {
car := Vehicles.Car{}
setModel(&car)
// model ("BMW") will be available here
}
func setModel(car *Vehicles.Car) {
car.Model = "BMW"
}

How to identify the stack size of goroutine?

I know go routine can have a few blocking actions, wonder if a goroutine can call a user-defined blocking function like a regular function. A user-defined blocking function has a few steps like, step1, step2.
In another word, I would like to find out whether we can have nested blocking calls in a go routine.
UPDATE:
Original intention was to find the stack size used by goroutine, especially with nested blocking calls. Sorry for the confusion. Thanks to the answer and comments, I created the following function that has 100,000 goroutines, it took 782MB of virtual memory and 416MB of Resident memory on my Ubuntu desktop. It evens out to be 78KB of memory for each go routine stack. Is this a correct statement?
package main
import (
"fmt"
"time"
)
func f(a int) {
x := f1(a);
f2(x);
}
func f1(a int) int {
r := step("1a", a);
r = step("1b", r);
return 1000 * a;
}
func f2(a int) {
r := step("2a", a);
r = step("2b", r);
}
func step(a string, b int) int{
fmt.Printf("%s %d\n", a, b);
time.Sleep(1000 * time.Second)
return 10 * b;
}
func main() {
for i := 0; i < 100000; i++ {
go f(i);
}
//go f(20);
time.Sleep(1000 * time.Second)
}
I believe you're right, though I'm unsure of the relationship between "virtual" and "resident" memory it's possible there's some overlap.
Some things to consider: you're running 100,000 it appears, not 10,000.
The stack itself might contain things like the strings used for the printfs, method parameters, etc.
As of go 1.2 the default stack size (per go routine) is 8KB which may explain some of it.
As of go 1.3 it also uses an exponentially increasing stack size, but I doubt that's the problem you're running into.
Short answer yes.
A goroutine is a "lightweight thread", that means it can do stuff independently from other code in your program. It's almost as if you started a new program, but you can communicate with your other code using the constructs golang provides (channels, locks, etc.).
P.S. Once the main function ends, all goroutines are killed (that's why you need the time.Sleep() in the example)
Here's the quick example (won't run in the golang playground because of their constraints):
package main
import (
"fmt"
"time"
)
func saySomething(a, b func()){
a()
b()
}
func foo() {
fmt.Println("foo")
}
func bar() {
fmt.Println("bar")
}
func talkForAWhile() {
for {
saySomething(foo, bar)
}
}
func main() {
go talkForAWhile()
time.Sleep(1 * time.Second)
}

Issue with runtime.LockOSThread() and runtime.UnlockOSThread

I have a code like,
Routine 1 {
runtime.LockOSThread()
print something
send int to routine 2
runtime.UnlockOSThread
}
Routine 2 {
runtime.LockOSThread()
print something
send int to routine 1
runtime.UnlockOSThread
}
main {
go Routine1
go Routine2
}
I use run time lock-unlock because, I don't want that printing of
Routine 1 will mix with Routine 2. However, after execution of above
code, it outputs same as without lock-unlock (means printing outputs
mixed). Can anybody help me why this thing happening and how to force
this for happening.
NB: I give an example of print something, however there are lots of
printing and sending events.
If you want to serialize "print something", e.g. each "print something" should perform atomically, then just serialize it.
You can surround "print something" by a mutex. That'll work unless the code deadlock because of that - and surely it easily can in a non trivial program.
The easy way in Go to serialize something is to do it with a channel. Collect in a (go)routine everything which should be printed together. When collection of the print unit is done, send it through a channel to some printing "agent" as a "print job" unit. That agent will simply receive its "tasks" and atomically print each one. One gets that atomicity for free and as an important bonus the code can not deadlock easily no more in the simple case, where there are only non interdependent "print unit" generating goroutines.
I mean something like:
func printer(tasks chan string) {
for s := range tasks {
fmt.Printf(s)
}
}
func someAgentX(tasks chan string) {
var printUnit string
//...
tasks <- printUnit
//...
}
func main() {
//...
tasks := make(chan string, size)
go printer(tasks)
go someAgent1(tasks)
//...
go someAgentN(tasks)
//...
<- allDone
close(tasks)
}
What runtime.LockOSThread does is prevent any other goroutine from running on the same thread. It forces the runtime to create a new thread and run Routine2 there. They are still running concurrently but on different threads.
You need to use sync.Mutex or some channel magic instead.
You rarely need to use runtime.LockOSThread but it can be useful for forcing some higher priority goroutine to run on a thread of it's own.
package main
import (
"fmt"
"sync"
"time"
)
var m sync.Mutex
func printing(s string) {
m.Lock() // Other goroutines will stop here if until m is unlocked
fmt.Println(s)
m.Unlock() // Now another goroutine at "m.Lock()" can continue running
}
func main() {
for i := 0; i < 10; i++ {
go printing(fmt.Sprintf("Goroutine #%d", i))
}
<-time.After(3e9)
}
I think, this is because of runtime.LockOSThread(),runtime.UnlockOSThread does not work all time. It totaly depends on CPU, execution environment etc. It can't be forced by anyother way.

Resources