├── Mutex
├── README.md
├── main.go
└── raceConditions
│ ├── README.md
│ └── main.go
├── README.md
├── channels
├── README.md
├── bidirectional
│ └── main.go
├── bufferedChannels
│ └── main.go
├── main.go
└── select
│ └── select.go
├── exercicios
├── BankBalance
│ ├── main.go
│ └── readme.md
├── barberShop
│ ├── README.md
│ └── main.go
├── diningPhilosophers
│ ├── README.md
│ └── main.go
└── pizzaria
│ ├── README.md
│ └── main.go
├── go.mod
├── go.sum
├── goroutine
├── README.md
└── main.go
└── waitGroups
├── README.md
├── main.go
└── main_test.go
/Mutex/README.md:
--------------------------------------------------------------------------------
1 | ## Mutex
2 |
3 | 
4 |
5 |
6 |
7 | Mutex permite que você lide com situação de race condition (concorrência)
8 | Você pode dar lock em um dado enquanto estiver usando, e após terminar é só dar unlock.
9 |
10 | Dessa maneira as goroutines irão acessar o dado com segurança.
11 | Caso o dado esteja em lock, e outra goroutine tente acessar, ela irá esperar até que o dado esteja disponivel.
12 |
13 | ## Exemplo
14 |
15 | ```go
16 | func updateMessage(s string, m *sync.Mutex) {
17 | defer wg.Done()
18 | m.Lock()
19 | msg = s
20 | m.Unlock()
21 | }
22 |
23 | func main() {
24 |
25 | var mutex sync.Mutex
26 |
27 | wg.Add(2)
28 | updateMessage("Message 2", &mutex)
29 | updateMessage("Message 1", &mutex)
30 | wg.Wait()
31 |
32 | fmt.Println(msg)
33 | }
34 | ```
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Mutex/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | var msg string
9 | var wg sync.WaitGroup
10 |
11 | func updateMessage(s string, m *sync.Mutex) {
12 |
13 | defer wg.Done()
14 |
15 | m.Lock()
16 | msg = s
17 | m.Unlock()
18 | }
19 |
20 | func main() {
21 |
22 | var mutex sync.Mutex
23 |
24 | wg.Add(2)
25 | updateMessage("Message 2", &mutex)
26 |
27 | updateMessage("Message 1", &mutex)
28 |
29 | wg.Wait()
30 |
31 | fmt.Println(msg)
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Mutex/raceConditions/README.md:
--------------------------------------------------------------------------------
1 | go run -race .
2 |
--------------------------------------------------------------------------------
/Mutex/raceConditions/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | var msg string
9 | var wg sync.WaitGroup
10 |
11 | func updateMessage(s string) {
12 | defer wg.Done()
13 | msg = s
14 | }
15 |
16 | func main() {
17 |
18 | wg.Add(2)
19 | go updateMessage("Teste 1")
20 | go updateMessage("Teste 2")
21 | wg.Wait()
22 |
23 | fmt.Println(msg)
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Repositório.
2 | Esse repo contem explicações e exemplos utilizando `goroutines`, `waitGroups`, `channels` e `mutex`. Cada um dos temas tem seu próprio readme com uma breve explicação.
3 | Você também ira encontrar uma lista com alguns exercícios conhecidos para praticar concorrência. Juntamente com a explicação e a resolução do problema.
4 |
5 | 
6 | Contribua!! 
7 |
8 |
9 | 
10 | 
11 | 
12 |
13 |
14 |
15 | # Tópicos
16 |
17 | - [Goroutines](https://github.com/mariarobertap/go-concurrency/tree/main/goroutine)
18 | - [Waigroups](https://github.com/mariarobertap/go-concurrency/tree/main/waitGroups)
19 | - [Channels](https://github.com/mariarobertap/go-concurrency/tree/main/channels)
20 | - [Mutex](https://github.com/mariarobertap/go-concurrency/tree/main/Mutex)
21 |
22 |
23 | # Exercícios
24 |
25 | - [Barbearia](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/barberShop)
26 | - [Pizzaria](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/pizzaria)
27 | - [Banco](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/BankBalance)
28 | - [Dining Philosophers](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/diningPhilosophers)
29 |
30 |
--------------------------------------------------------------------------------
/channels/README.md:
--------------------------------------------------------------------------------
1 |
O que são Channels?
2 |
3 | 
4 |
5 |
6 |
7 | Um channel é um sistema de comunicação que permite uma go-routine enviar valores a outra go-routine.
8 | O channel nada mais é do que um cano utilizado para transmitir informações entre go-routines.
9 |
10 | Como criar um channel?
11 |
12 | ```go
13 | ch := make(chan int)
14 | ```
15 |
16 | Tipos de canais
17 |
18 | Os canais podem ser especificos ou gerais ou seja eles podem ser unidirecionais ou bidirecionais.
19 |
20 | Exemplo de canal bidirecional:
21 |
22 | ```go
23 | ch := make(chan string)
24 | ```
25 | Este canal pode ser convertido para um canal especifico(send ou receive)
26 |
27 | Exemplo de canais unidirecionais:
28 |
29 | ```go
30 | // canal de envio
31 | cs := ch<-
32 | //canal de recebimento
33 | cr := <-ch
34 | ```
35 | Canais unidirecionais não podem ser convertidos para bidirecional nem de um send para um receive depois de sua declaração
36 |
37 | exemplos:
38 | ```go
39 | //only bidirectional channels can become send or receive channels
40 | package main
41 | //it works :)
42 | func main(){
43 | channel := make(chan string)
44 | channelSend := func() {
45 | channel <- "Hello"
46 | }
47 | go channelSend()
48 | channelReceive := <-channel
49 | fmt.Println(channelReceive)
50 | }
51 |
52 | ```
53 | ```go
54 | package main
55 | //It doesn't work :(
56 | func main(){
57 | cs := make(chan<-string)
58 | cr := make(<-chan string)
59 |
60 | (<-chan string)(cs)
61 | (chan<- string)(cr)
62 | (chan string)(cs)
63 | (chan string)(cr)
64 | }
65 | ```
66 |
67 | Exemplo usando funções:
68 |
69 | ```go
70 | package main
71 |
72 | import "fmt"
73 |
74 | func sendNumber(cs chan<- int64, number int64){
75 | cs <- number
76 | }
77 | func receiveAndReturnANumber(cr <-chan int64)int64{
78 | number := <-cr
79 | return number
80 | }
81 | func main(){
82 | ch := make(chan int64)
83 | go sendNumber(ch,1075897489377463545)
84 | number := receiveAndReturnANumber(ch)
85 | fmt.Println(number)
86 | }
87 | ```
88 |
89 | "Don't communicate by sharing memory; share memory by communicating. (R. Pike)"
90 |
--------------------------------------------------------------------------------
/channels/bidirectional/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | messagesChannel := make(chan string)//bidirectional channel
8 |
9 | go sendMessage(messagesChannel,"Oi do sendMessage")//send channel
10 | receiveMessage(messagesChannel)//receive channel
11 | }
12 |
13 | func sendMessage(cs chan<- string,message string){
14 | cs<-message
15 | }
16 |
17 | func receiveMessage(cr <-chan string){
18 | fmt.Printf(<-cr)
19 | }
20 |
--------------------------------------------------------------------------------
/channels/bufferedChannels/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 |
10 | //This channel have a buffer of 10. I can put 10 values in this channel.
11 | //Everytime the listenToChan function get the value from the chan, i get one free space..
12 | ch := make(chan int, 10)
13 |
14 | go listenToChannel(ch)
15 |
16 | for i := 0; i < 100; i++ {
17 |
18 | fmt.Println("sendind data to channel", i)
19 |
20 | ch <- i
21 | fmt.Println("Sent data to channel", i)
22 |
23 | }
24 |
25 | close(ch)
26 |
27 | }
28 |
29 | func listenToChannel(ch chan int) {
30 |
31 | for {
32 | i := <-ch
33 |
34 | fmt.Println("Got", i, " from channel")
35 |
36 | time.Sleep(1 * time.Second)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/channels/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | func main() {
9 | ping := make(chan string)
10 | pong := make(chan string)
11 | var userInput string
12 |
13 | go shout(ping, pong)
14 |
15 | for {
16 |
17 | fmt.Print("->")
18 |
19 | fmt.Scanln(&userInput)
20 |
21 | if userInput == "q" {
22 | break
23 | }
24 |
25 | ping <- userInput
26 |
27 | response := <-pong
28 |
29 | fmt.Println(response)
30 |
31 | }
32 | close(ping)
33 | close(pong)
34 | }
35 |
36 | //Receiver and sender. receiver <-chan. sender chan<-
37 | func shout(receiver <-chan string, sender chan<- string) {
38 |
39 | for {
40 | s, ok := <-receiver
41 | if !ok {
42 | fmt.Println("Channel is closed.")
43 | }
44 | sender <- fmt.Sprintf("%s!!", strings.ToUpper(s))
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/channels/select/select.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | fmt.Println("----- SELECT WITH CHANNELS -----")
10 | ch1 := make(chan string)
11 | ch2 := make(chan string)
12 |
13 | go server1(ch1)
14 | go server2(ch2)
15 |
16 | for {
17 | //Note that case 1 and 2, and 3 and 4 are exactly the same. if this happens, go will choose randomly.
18 | select {
19 | case s1 := <-ch1:
20 | fmt.Println("CASE 1 - ", s1)
21 | case s2 := <-ch1:
22 | fmt.Println("CASE 2 - ", s2)
23 | case s3 := <-ch2:
24 | fmt.Println("CASE 3 - ", s3)
25 | case s4 := <-ch2:
26 | fmt.Println("CASE 4 - ", s4)
27 | //default - default case can also be used to avoid deadlocks
28 | }
29 | }
30 |
31 | }
32 |
33 | func server1(ch chan string) {
34 | for {
35 | time.Sleep(1 * time.Second)
36 | ch <- "SERVER1. This is a message sent from server 1."
37 | }
38 | }
39 | func server2(ch chan string) {
40 | for {
41 | time.Sleep(1 * time.Second)
42 | ch <- "SERVER 2. This is a message sent from server 2."
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/exercicios/BankBalance/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | var wg sync.WaitGroup
9 |
10 | type Income struct {
11 | Source string
12 | Amount int
13 | }
14 |
15 | func main() {
16 |
17 | var bankBalance int
18 | var balance sync.Mutex
19 |
20 | income := []Income{
21 | {
22 | Source: "Main job",
23 | Amount: 1000,
24 | },
25 | {
26 | Source: "Investments",
27 | Amount: 500,
28 | },
29 | }
30 |
31 | wg.Add(len(income))
32 | for i := 0; i < len(income); i++ {
33 |
34 | go func(i int, income Income) {
35 | defer wg.Done()
36 | for week := 0; week < 4; week++ {
37 | balance.Lock()
38 | temp := bankBalance
39 | temp += income.Amount
40 | bankBalance = temp
41 | balance.Unlock()
42 |
43 | }
44 |
45 | }(i, income[i])
46 |
47 | }
48 | wg.Wait()
49 |
50 | fmt.Printf("Total amount earned $ %d", bankBalance)
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/exercicios/BankBalance/readme.md:
--------------------------------------------------------------------------------
1 | BankBalance
2 |
--------------------------------------------------------------------------------
/exercicios/barberShop/README.md:
--------------------------------------------------------------------------------
1 | A barbershop consist of a waiting room with n chairs, and a barber room with one barber chair. Given the following constraints:
2 |
3 | If there are no customers to be served, the barber goes to sleep
4 | If a customer enters the barbershop and all chairs are occupied, then the customer leaves the shop.
5 | If the barber is busy, but chairs are available, then the customer sits in one of the free chairs.
6 | If the barber is sleeping, the customer wakes up the barber.
7 |
--------------------------------------------------------------------------------
/exercicios/barberShop/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "time"
7 |
8 | "github.com/fatih/color"
9 | )
10 |
11 | var seatingCapacity = 10
12 | var arrivalRate = 100
13 | var cutDuration = 1000 * time.Millisecond
14 | var timeOpen = 10 * time.Second
15 |
16 | type BarberShop struct {
17 | ShopCapacity int
18 | HairCutDuration time.Duration
19 | NumberOfBarbers int
20 | BarbersDoneChan chan bool
21 | ClientsChan chan string
22 | Open bool
23 | }
24 |
25 | func main() {
26 |
27 | rand.Seed(time.Now().UnixNano())
28 |
29 | color.Yellow("The Sleeping Barber Problem")
30 | color.Yellow("---------------------------")
31 |
32 | //Esse é um buffered channel, com o tamanho == ao tamanho da capacidade de clientes da barbearia.
33 | clientChan := make(chan string, seatingCapacity)
34 | doneChan := make(chan bool)
35 |
36 | shop := BarberShop{
37 | ShopCapacity: seatingCapacity,
38 | HairCutDuration: cutDuration,
39 | NumberOfBarbers: 0,
40 | ClientsChan: clientChan,
41 | BarbersDoneChan: doneChan,
42 | Open: true,
43 | }
44 |
45 | color.Green("The shop is open for the day")
46 |
47 | shop.AddBarber("Frank")
48 | shopClosing := make(chan bool)
49 | closed := make(chan bool)
50 |
51 | //Verificando se 10s já se passaram para fechar a loja
52 | go func() {
53 | //Waiting until is time to close the store.
54 | <-time.After(timeOpen)
55 | shopClosing <- true
56 | shop.closeShopForDay()
57 | closed <- true
58 |
59 | }()
60 |
61 | i := 0
62 | //Enviando clientes para a barbearia.
63 | go func() {
64 | for {
65 | //get a random number with average arrival date
66 | random := rand.Int() % (2 * arrivalRate)
67 | select {
68 | case <-shopClosing:
69 | return
70 | case <-time.After(time.Millisecond * time.Duration(random)):
71 | shop.addClient(fmt.Sprintf("Maria #%d", i))
72 | i++
73 |
74 | }
75 | }
76 | }()
77 |
78 | //Esperando até que tudo estiver finalizado.
79 | <-closed
80 |
81 | }
82 |
83 | func (shop *BarberShop) AddBarber(barberName string) {
84 | shop.NumberOfBarbers++
85 | go func() {
86 | isSleeping := false
87 |
88 | color.Yellow(" %s Goes to the waiting room to check for clients.", barberName)
89 |
90 | for {
91 | if len(shop.ClientsChan) == 0 {
92 | color.Yellow("%s Takes a nap. No clients in the waiting room", barberName)
93 | isSleeping = true
94 | }
95 |
96 | //Verifica se o canal está fechado.
97 | //Se estiver, significa que a loja está fechada.
98 | //Mas como é um buffered channel, ainda pode ter dados no buffer.
99 | //Atendendo o critério do exercicio, que se a loja estiver fechada
100 | //ainda pode ter clientes na sala de espera.
101 | client, open := <-shop.ClientsChan
102 |
103 | if open {
104 | if isSleeping {
105 | color.Yellow("Client %s wakes up %s", client, barberName)
106 | isSleeping = false
107 | }
108 |
109 | shop.cutHair(barberName, client)
110 |
111 | } else {
112 | shop.sendBarberHome(barberName)
113 | return
114 | }
115 | }
116 | }()
117 | }
118 |
119 | func (shop *BarberShop) cutHair(barberName, client string) {
120 | color.Green("%s is cutting %s hair", barberName, client)
121 | time.Sleep(shop.HairCutDuration)
122 | }
123 |
124 | func (shop *BarberShop) sendBarberHome(barberName string) {
125 | color.Cyan("%s is going home", barberName)
126 | shop.BarbersDoneChan <- true
127 |
128 | }
129 | func (shop *BarberShop) closeShopForDay() {
130 |
131 | color.Cyan("Closing shop for the day")
132 | //Fechando o canal para não aceitar novos clientes na sala de espera.
133 | //Os que ainda estáo esperando, continuam até serem atendidos.
134 | close(shop.ClientsChan)
135 | shop.Open = false
136 |
137 | for i := 0; i < shop.NumberOfBarbers; i++ {
138 | //esperando receber um valor aqui ==
139 | <-shop.BarbersDoneChan
140 |
141 | }
142 |
143 | close(shop.BarbersDoneChan)
144 |
145 | color.Green("-------------------")
146 | color.Green("Barber shop is closed")
147 |
148 | }
149 |
150 | func (shop *BarberShop) addClient(client string) {
151 | color.Green("*** %s arrives! ", client)
152 |
153 | if shop.Open {
154 | select {
155 | case shop.ClientsChan <- client:
156 | color.Blue("%s Takes a seat in the waiting room", client)
157 | default:
158 | //Buffered channel is full
159 | color.Red("Waiting room is full %s leaves", client)
160 | }
161 |
162 | } else {
163 | color.Red("The shop is already closed, so %s leaves", client)
164 | }
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/exercicios/diningPhilosophers/README.md:
--------------------------------------------------------------------------------
1 | The dining philosophers problem states that there are 5 philosophers sharing a circular table and they eat and think alternatively. There is a bowl of rice for each of the philosophers and 5 chopsticks. A philosopher needs both their right and left chopstick to eat. A hungry philosopher may only eat if there are both chopsticks available.Otherwise a philosopher puts down their chopstick and begin thinking again.
2 |
3 | The dining philosopher is a classic synchronization problem as it demonstrates a large class of concurrency control problems.
4 |
--------------------------------------------------------------------------------
/exercicios/diningPhilosophers/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 | type Philosopher struct {
10 | name string
11 | rightFork int
12 | leftFork int
13 | }
14 |
15 | var philosofers = []Philosopher{
16 | {name: "Plato", leftFork: 4, rightFork: 0},
17 | {name: "Socrates", leftFork: 0, rightFork: 1},
18 | {name: "Aristotle", leftFork: 1, rightFork: 2},
19 | {name: "Pascal", leftFork: 2, rightFork: 3},
20 | {name: "Locke", leftFork: 3, rightFork: 4},
21 | }
22 |
23 | //
24 | var hunger = 1 // how many times does a person eat?
25 | var eatTime = 1 * time.Second
26 | var thinkTime = 3 * time.Second
27 | var sleepTime = 1 * time.Second
28 | var listPhilosofers []string
29 |
30 | func main() {
31 | fmt.Println("Dining philosophers problem")
32 | fmt.Println("---------------------------")
33 | fmt.Println("The table is empty.")
34 |
35 | dine()
36 |
37 | fmt.Println("The table is empty.")
38 |
39 | }
40 |
41 | func dine() {
42 |
43 | wg := &sync.WaitGroup{}
44 | wg.Add(len(philosofers))
45 |
46 | seated := &sync.WaitGroup{}
47 | seated.Add(len(philosofers))
48 | list := &sync.Mutex{}
49 |
50 | var forks = make(map[int]*sync.Mutex)
51 |
52 | for i := 0; i < len(philosofers); i++ {
53 | forks[i] = &sync.Mutex{}
54 | }
55 |
56 | //Start the meal.
57 | for i := 0; i < len(philosofers); i++ {
58 | //Fire of a goroutine for the current philosopher
59 | go diningProblem(philosofers[i], wg, forks, seated, list)
60 |
61 | }
62 |
63 | wg.Wait()
64 | fmt.Println(listPhilosofers)
65 |
66 | }
67 |
68 | func diningProblem(philosopher Philosopher, wg *sync.WaitGroup, forks map[int]*sync.Mutex, seated *sync.WaitGroup, list *sync.Mutex) {
69 | defer wg.Done()
70 |
71 | //seat the philoshphers at the table
72 |
73 | fmt.Printf("%s is seated at the table.\n", philosopher.name)
74 |
75 | seated.Done()
76 | //Wait until everyone is seated.
77 | seated.Wait()
78 |
79 | for i := 0; i < hunger; i++ {
80 | //get a lock on both forks
81 | if philosopher.leftFork > philosopher.rightFork {
82 | forks[philosopher.rightFork].Lock()
83 | fmt.Printf(" %s Takes the rifht fork.\n", philosopher.name)
84 | forks[philosopher.leftFork].Lock()
85 | fmt.Printf(" %s Takes the left fork.\n", philosopher.name)
86 |
87 | } else {
88 | forks[philosopher.leftFork].Lock()
89 | fmt.Printf(" %s Takes the left fork.\n", philosopher.name)
90 | forks[philosopher.rightFork].Lock()
91 | fmt.Printf(" %s Takes the rifht fork.\n", philosopher.name)
92 | }
93 |
94 | fmt.Printf(" %s has both forks, is eating..\n", philosopher.name)
95 | time.Sleep(eatTime)
96 | forks[philosopher.leftFork].Unlock()
97 | forks[philosopher.rightFork].Unlock()
98 |
99 | fmt.Printf(" %s Is done eating.\n", philosopher.name)
100 |
101 | }
102 | list.Lock()
103 | listPhilosofers = append(listPhilosofers, philosopher.name)
104 | list.Unlock()
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/exercicios/pizzaria/README.md:
--------------------------------------------------------------------------------
1 | Pizzaria
2 |
--------------------------------------------------------------------------------
/exercicios/pizzaria/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "time"
7 |
8 | "github.com/fatih/color"
9 | )
10 |
11 | const NumberOfPizzas = 10
12 |
13 | var pizzasMade, pizzasFailed, total int
14 |
15 | type Producer struct {
16 | data chan PizzaOrder
17 | quit chan chan error
18 | }
19 |
20 | type PizzaOrder struct {
21 | pizzaNumber int
22 | message string
23 | success bool
24 | }
25 |
26 | func makePizza(pizzaId int) *PizzaOrder {
27 | pizzaId++
28 |
29 | if pizzaId <= NumberOfPizzas {
30 | delay := rand.Intn(5) + 1
31 | fmt.Printf("Received order # %d\n", pizzaId)
32 |
33 | rnd := rand.Intn(12) + 1
34 | msg := ""
35 | success := false
36 |
37 | if rnd < 5 {
38 | pizzasFailed++
39 |
40 | } else {
41 | pizzasMade++
42 |
43 | }
44 | total++
45 |
46 | fmt.Printf("Makind pizza #%d. It will take %d seconds....\n", pizzaId, delay)
47 | time.Sleep(time.Duration(delay) * time.Second)
48 |
49 | if rnd <= 2 {
50 | msg = fmt.Sprintf("We ran out of ingredients for pizza #%d\n", pizzaId)
51 | } else if rnd <= 4 {
52 | msg = fmt.Sprintf("***The cook quit while making the pizza #%d\n", pizzaId)
53 | } else {
54 | success = true
55 | msg = fmt.Sprintf("Pizza order #%d is ready!\n", pizzaId)
56 |
57 | }
58 |
59 | return &PizzaOrder{
60 | pizzaNumber: pizzaId,
61 | message: msg,
62 | success: success,
63 | }
64 | }
65 |
66 | return &PizzaOrder{
67 | pizzaNumber: pizzaId,
68 | }
69 | }
70 |
71 | func pizzaria(pizzaJob *Producer) {
72 | var i = 0
73 |
74 | for {
75 | currentPizza := makePizza(i)
76 | if currentPizza != nil {
77 | i = currentPizza.pizzaNumber
78 | select {
79 | case pizzaJob.data <- *currentPizza:
80 |
81 | case quitChan := <-pizzaJob.quit:
82 | close(pizzaJob.data)
83 | close(quitChan)
84 | return
85 | }
86 | }
87 |
88 | }
89 |
90 | }
91 |
92 | func (p *Producer) Close() error {
93 | ch := make(chan error)
94 |
95 | p.quit <- ch
96 |
97 | return <-ch
98 | }
99 |
100 | func main() {
101 | rand.Seed(time.Now().UnixNano())
102 | color.Cyan("The Pizzaria is open for bussiness")
103 | color.Cyan("----------------------------------")
104 |
105 | pizzaJob := &Producer{
106 | data: make(chan PizzaOrder),
107 | quit: make(chan chan error),
108 | }
109 |
110 | go pizzaria(pizzaJob)
111 |
112 | //CONSUMER - consumes the pizzaria data
113 | for i := range pizzaJob.data {
114 | if i.pizzaNumber <= NumberOfPizzas {
115 | if i.success {
116 | color.Green(i.message)
117 | color.Green("Order %d is out for delivery!", i.pizzaNumber)
118 | } else {
119 | color.Red(i.message)
120 | color.Red("The customer is really mad!")
121 | }
122 | } else {
123 | color.Cyan("Done making pizzas!")
124 | color.Cyan("----------------------------------")
125 | err := pizzaJob.Close()
126 | if err != nil {
127 | color.Red("Error closing channel!")
128 |
129 | }
130 | }
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module waitGroups
2 |
3 | go 1.18
4 |
5 | require github.com/fatih/color v1.13.0
6 |
7 | require (
8 | github.com/mattn/go-colorable v0.1.9 // indirect
9 | github.com/mattn/go-isatty v0.0.14 // indirect
10 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
11 | )
12 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
2 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
3 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
4 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
5 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
6 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
7 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
8 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
9 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
11 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
12 |
--------------------------------------------------------------------------------
/goroutine/README.md:
--------------------------------------------------------------------------------
1 | Goroutine
2 |
3 | Se você já utilizou threads em outra linguagem, pode supor que as goroutines são similares as threads,
4 | uma das diferença é que as goroutines são muito mais leves.
5 | Uma goroutine nada mais é do que uma atividade que é execudada de forma concorrente.
6 | Você pode ter diversas atividades em um mesmo programa rodando de forma concorrente.
7 |
8 | Exemplo
9 | ```go
10 | package main
11 |
12 | import (
13 | "fmt"
14 | "sync"
15 | )
16 |
17 | func printSomething(s string, wg *sync.WaitGroup) {
18 | defer wg.Done()
19 | fmt.Println(s)
20 | }
21 |
22 | func main() {
23 | var wg sync.WaitGroup
24 |
25 | wg.Add(1)
26 | go printSomething("Hello from goroutine 1", &wg)
27 | fmt.Println("Hello from main-goroutine.")
28 | wg.Wait()
29 |
30 | }
31 | ```
32 |
--------------------------------------------------------------------------------
/goroutine/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | func printSomething(s string, wg *sync.WaitGroup) {
9 | defer wg.Done()
10 | fmt.Println(s)
11 | }
12 |
13 | func main() {
14 | var wg sync.WaitGroup
15 |
16 | wg.Add(1)
17 | go printSomething("Hello from goroutine 1", &wg)
18 | fmt.Println("Hello from main-goroutine.")
19 |
20 | wg.Wait()
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/waitGroups/README.md:
--------------------------------------------------------------------------------
1 | # WaitGroups
2 |
3 | Levando em conta que GoRoutines são funções que são executadas em paralelo como uma thread, seu programa pode finalizar antes que sua GoRoutine finalize.
4 | Para contornar isso, existe os waitGroups, utilizados para informar ao seu programa que ele deve aguardar por uma ou mais GoRoutines finalizar
5 |
6 |
7 | - WaitGroup espera por uma quantidade de goroutines finalizar. Impedindo que seu programa finalize antes que as go routines terminem de rodar.
8 | - As go routines são responsáveis por avisar que ela está finalizada.
9 |
10 | # Exemplo:
11 | ```go
12 | var wg sync.WaitGroup
13 |
14 | func hello() {
15 | //Goroutine Avisando ao WaitGroup que finalizou.
16 | defer wg.Done()
17 | fmt.Println("hello from a goroutine!")
18 | }
19 |
20 | func main() {
21 | //wait group deve esperar por 1 goroutine finalizar
22 | wg.Add(1)
23 | //Go routine
24 | go hello()
25 | //Esperando Goroutine finalizar.
26 | wg.Wait()
27 | }
28 | ```
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/waitGroups/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | func printSomething(s string, wg *sync.WaitGroup) {
9 | defer wg.Done()
10 | fmt.Println(s)
11 | }
12 |
13 | func main() {
14 | var wg sync.WaitGroup
15 | words := []string{
16 | "test1",
17 | "test2",
18 | "test3",
19 | "test4",
20 | "test5",
21 | "test6",
22 | }
23 |
24 | wg.Add(len(words))
25 |
26 | for i := 0; i < len(words); i++ {
27 | go printSomething(words[i], &wg)
28 | }
29 |
30 | wg.Wait()
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/waitGroups/main_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "io"
5 | "os"
6 | "strings"
7 | "sync"
8 | "testing"
9 | )
10 |
11 | func Test_printSomething(t *testing.T) {
12 | var wg sync.WaitGroup
13 | stdOut := os.Stdout
14 | r, w, _ := os.Pipe()
15 | os.Stdout = w
16 | expectedString := "testando"
17 | wg.Add(1)
18 |
19 | go printSomething(expectedString, &wg)
20 |
21 | wg.Wait()
22 |
23 | _ = w.Close()
24 |
25 | result, _ := io.ReadAll(r)
26 | output := string(result)
27 |
28 | os.Stdout = stdOut
29 |
30 | if !strings.Contains(output, expectedString) {
31 | t.Errorf("Expected = %s; Got = %s", expectedString, output)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------