/* Taken from http://gist.github.com/drio/dd2c4ad72452e3c35e7e Modified: J.Kobus 12-2017 Usage: go run prod-cons.go [-e ] workTimeProd workTimeCons workTimeProd workTimeCons -- (integer) time (in milliseconds) spent in producing/consuming an item Use "go build prod-cond.go" to build the executable prod-cons. See also http://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65 http://golangbot.com/goroutines/ Goroutines are extremely cheap when compared to threads. They are only a few kb in stack size and the stack can grow and shrink according to needs of the application whereas in the case of threads the stack size has to be specified and is fixed. The Goroutines are multiplexed to fewer number of OS threads. There might be only one thread in a program with thousands of Goroutines. If any Goroutine in that thread blocks, say, waiting for user input, then another OS thread is created and the remaining Goroutines are moved to the new OS thread. All these are taken care by the runtime and we as programmers are abstracted from these intricate details and are given a clean API to work with concurrency. Goroutines communicate using channels. Channels by design prevent race conditions from happening when accessing shared memory using Goroutines. Channels can be thought of as a pipe using which Goroutines communicate. We will discuss channels in detail in the next tutorial. */ package main // Tell go runtime your main lives here import ("fmt") // We need the fmt package to print to the stdout import ("time" "flag" "strconv" ) /* These next two lines create two new channels, which are one of the concurrency constructs golang offers. The first channel is a boolean channel the second one is an int channel. We can read or write data to the channels. We will see how shortly. */ var done = make(chan bool) var msgs = make(chan int, 5) /* In our main function, we spawn two go routines. go routines are cheap functions that will be run concurrently by go runtime. They are just regular functions, but using the keyword go before a function call we can run them as go routines. So those two functions will run concurrently. Finally we block the main thread by reading from the done channel. As soon something comes down the channel, we read it, toss it and the main thread continues executing. In this case we exit the program. */ func main () { var workTime []string var slots int var els int slots = 5 elsPtr := flag.Int("e", 10, "an int") flag.Parse() els = *elsPtr fmt.Println("liczba elementów: ", els) fmt.Println("liczba przegródek: ",slots) workTime = flag.Args() workTimeProd, err := strconv.Atoi(workTime[0]) workTimeCons, err := strconv.Atoi(workTime[1]) _ = err fmt.Println(" ") fmt.Println("czas produkcji: ", workTimeProd, "ms") fmt.Println("czas konsumpcji: ", workTimeCons, "ms") fmt.Println(" ") go produce(els,workTimeProd) go consume(els,workTimeCons) <- done // check what happens when the following line is commented out time.Sleep(time.Duration(1000) * time.Millisecond) } /* The produce go routine (or function) loops imax times and writes an integer (0..imax) in the msg channel. Notice that we will block until someone (the consumer) reads from the other side of the channel. Once we are done, we send a boolean on the done channel to let the main go routine that we are done. */ func produce(imax int, worktime int) { for i := 1; i <=imax; i++ { msgs <- i fmt.Println("produce:",i) time.Sleep(time.Duration(worktime) * time.Millisecond) } done <- true } /* The consume go routine loops infinitely and reads on the msgs channel. It will block until something comes in the channel. The syntax can be a little bit strange for people coming from other languages. ':=' creates a variable assigning it the type of the value coming on the right of the assignation. An int in this case. '<-' is the go way to read from a channel. Once we have the msg (int) we dump it in the stdout. */ func consume(imax int, worktime int) { for { time.Sleep(time.Duration(worktime) * time.Millisecond) msg := <-msgs fmt.Println(" consume:",msg) } }