├── README.md ├── dining_philosophers ├── dining_philosophers.go └── dining_philosophers.py ├── producer_consumer ├── producer_consumer.go └── producer_consumer.py ├── readers_writer ├── reader_writer.go └── reader_writer.py └── sleeping_barber ├── sleeping_barber.go └── sleeping_barber.py /README.md: -------------------------------------------------------------------------------- 1 | # Threading comparison in Go and Python. 2 | 3 | ## Classical IPC Problems (solutions in golang and python) 4 | * Producer / Consumer 5 | * Reader / Writer 6 | * Sleeping barber 7 | * Dining philosophers 8 | 9 | ## Used 10 | threading, goroutines, Locks/Mutexes, Semaphores, Monitors, condition variables 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dining_philosophers/dining_philosophers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | var num_philosophers = 5 10 | var philosophers = make([]int, 0) 11 | var forks = make([]sync.Mutex, 0) 12 | var done = make(chan bool) 13 | 14 | func philosopher(idx int) { 15 | left_fork := idx 16 | right_fork := (idx-1) 17 | if right_fork < 0 { 18 | right_fork = num_philosophers - 1 19 | } 20 | for { 21 | forks[right_fork].Lock() 22 | forks[left_fork].Lock() 23 | fmt.Println("Philosopher:", idx, " eating, forks: ", 24 | left_fork, right_fork) 25 | time.Sleep(time.Duration(2)*time.Second) 26 | forks[right_fork].Unlock() 27 | forks[left_fork].Unlock() 28 | time.Sleep(time.Duration(1)*time.Second) 29 | } 30 | } 31 | 32 | func main() { 33 | fmt.Println("ol") 34 | for i := 0 ; i < num_philosophers; i+=1 { 35 | var lock = sync.Mutex{} 36 | forks = append(forks, lock) 37 | } 38 | for i := 0; i < num_philosophers; i+=1 { 39 | go philosopher(i) 40 | } 41 | <-done 42 | } 43 | 44 | -------------------------------------------------------------------------------- /dining_philosophers/dining_philosophers.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Lock 2 | from time import sleep 3 | 4 | num_philosophers = 5 5 | philosophers = [] 6 | forks = [] 7 | 8 | def philosopher(idx): 9 | left_fork = idx 10 | right_fork = (idx-1)%num_philosophers 11 | 12 | while (1): 13 | forks[right_fork].acquire() 14 | forks[left_fork].acquire() 15 | print("Philosopher: ", idx, " eating, forks: ", left_fork, right_fork) 16 | sleep(2) 17 | forks[right_fork].release() 18 | forks[left_fork].release() 19 | sleep(1) 20 | 21 | if __name__ == "__main__": 22 | for i in range(num_philosophers): 23 | P = Thread(target=philosopher, args=(i,)) 24 | philosophers.append(P) 25 | forks.append(Lock()) 26 | for P in philosophers: 27 | P.start() 28 | 29 | -------------------------------------------------------------------------------- /producer_consumer/producer_consumer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | var buffer_max = 4 10 | var buffer_chan = make(chan int, buffer_max) 11 | var buffer_copy = make([]int, 0) 12 | 13 | func producer() { 14 | for { 15 | write_this := rand.Intn(50) 16 | buffer_chan <-write_this 17 | buffer_copy = append(buffer_copy, write_this) 18 | fmt.Println(buffer_copy, " produced: ", write_this) 19 | time.Sleep(time.Duration(rand.Intn(3))*time.Second) 20 | } 21 | } 22 | 23 | func consumer(id int) { 24 | time.Sleep(time.Duration(1)*time.Second) 25 | for { 26 | read_this := <-buffer_chan 27 | buffer_copy = buffer_copy[1:] 28 | fmt.Println(buffer_copy, " consumer: ", id , " consumed: ", read_this) 29 | time.Sleep(time.Duration(rand.Intn(7-2)+2)*time.Second) 30 | } 31 | } 32 | 33 | func main() { 34 | done := make(chan bool) 35 | 36 | go producer() 37 | go consumer(1) 38 | go consumer(2) 39 | 40 | <-done 41 | } 42 | -------------------------------------------------------------------------------- /producer_consumer/producer_consumer.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Semaphore 2 | from random import randint 3 | from time import sleep 4 | 5 | buffer_max = 4 6 | buffer = [] 7 | 8 | sema_dont_below = Semaphore(0) 9 | sema_dont_above = Semaphore(buffer_max) 10 | 11 | def producer(): 12 | while (1): 13 | sema_dont_above.acquire() 14 | write_this = randint(0,50) 15 | buffer.append(write_this) 16 | sema_dont_below.release() 17 | print(buffer, " produced: ", write_this) 18 | sleep( randint(0,3) ) 19 | 20 | def consumer(id): 21 | sleep(1) 22 | while (1): 23 | sema_dont_below.acquire() 24 | read_this = buffer.pop(0) 25 | sema_dont_above.release() 26 | print(buffer, " consumer: ", id , " consumed: ", read_this) 27 | sleep( randint(2,7) ) 28 | 29 | if __name__ == "__main__": 30 | p = Thread(target=producer) 31 | c1 = Thread(target=consumer, args=(1,)) 32 | c2 = Thread(target=consumer, args=(2,)) 33 | 34 | p.start() 35 | c1.start() 36 | c2.start() 37 | 38 | p.join() 39 | c1.join() 40 | c2.join() 41 | -------------------------------------------------------------------------------- /readers_writer/reader_writer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | "math/rand" 7 | ) 8 | 9 | var channel = make(chan int, 1) 10 | var buffer = []int{0,1} 11 | var done = make(chan bool) 12 | 13 | func writer() { 14 | time.Sleep(time.Duration(rand.Intn(4-1)+1)*time.Second) 15 | <-channel // Lock 16 | buffer[0] += 1 17 | buffer[1] += 1 18 | fmt.Println("Wrote to buffer, buffer[0]:", buffer[0],"buffer[1]:",buffer[1]) 19 | channel <-1 // Unlock 20 | done <-true 21 | } 22 | 23 | func reader() { 24 | time.Sleep(time.Duration(rand.Intn(4-1)+1)*time.Second) 25 | <-channel // Lock 26 | fmt.Println("Read buffer[0]:", buffer[0]," buffer[1]:", buffer[1]) 27 | channel <-1 // Unlock 28 | done <-true 29 | } 30 | 31 | func main() { 32 | 33 | fmt.Println("lol") 34 | channel <-1 35 | 36 | for i := 0; i < 5; i++ { 37 | go reader() 38 | go reader() 39 | go reader() 40 | go writer() 41 | } 42 | for i := 0; i < 5; i++ { 43 | <-done 44 | <-done 45 | <-done 46 | <-done 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /readers_writer/reader_writer.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Semaphore, Lock 2 | from random import randint 3 | from time import sleep 4 | 5 | #semaphore = Semaphore(1) 6 | lock = Lock() 7 | 8 | buffer = [0,1] 9 | 10 | def writer(): 11 | sleep(randint(1,4)) 12 | #semaphore.acquire() 13 | lock.acquire() 14 | buffer[0] += 1 15 | buffer[1] += 1 16 | print("Wrote to buffer, buffer[0]:", buffer[0],"buffer[1]:",buffer[1]) 17 | #semaphore.release() 18 | lock.release() 19 | 20 | def reader(id): 21 | sleep(randint(1,4)) 22 | #semaphore.acquire() 23 | lock.acquire() 24 | print("Read buffer[0]:", buffer[0]," buffer[1]:", buffer[1]) 25 | #semaphore.release() 26 | lock.release() 27 | 28 | if __name__ == "__main__": 29 | threads = [] 30 | for i in range(5): 31 | for j in range(3): 32 | r = Thread(target=reader, args=(j,)) 33 | threads.append(r) 34 | w = Thread(target=writer) 35 | threads.append(w) 36 | for t in threads: 37 | t.start() 38 | for t in threads: 39 | t.join() 40 | 41 | -------------------------------------------------------------------------------- /sleeping_barber/sleeping_barber.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | import ( 5 | "fmt" 6 | "sync" 7 | "time" 8 | "math/rand" 9 | ) 10 | 11 | var condition = &sync.Cond{L: &sync.Mutex{}} 12 | var barber_available = false 13 | 14 | var customers_waiting = make([]int, 0) 15 | var seats = 3 16 | var done = make(chan bool) 17 | 18 | var threads sync.WaitGroup 19 | 20 | func cutting_hair(id int) { 21 | fmt.Println(id, ": Having a haircut") 22 | time.Sleep(time.Duration(rand.Intn(6-1)+1)*time.Second) 23 | fmt.Println(id, ": Done") 24 | } 25 | 26 | func barber() { 27 | print("Barber: Opening shop") 28 | for { 29 | condition.L.Lock() 30 | if len(customers_waiting) > 0 { 31 | id := customers_waiting[0] 32 | customers_waiting = customers_waiting[1:] 33 | condition.L.Unlock() 34 | barber_available = false 35 | cutting_hair(id) 36 | done <-true 37 | } else { 38 | fmt.Println("Barber: Going to sleep") 39 | for ; barber_available == false ; { 40 | condition.Wait() 41 | } 42 | condition.L.Unlock() 43 | fmt.Println("Barber: Woke up") 44 | } 45 | } 46 | } 47 | 48 | func customer(id int) { 49 | condition.L.Lock() 50 | if len(customers_waiting) == seats { 51 | fmt.Println(id, ": Leaving") 52 | done <-true 53 | condition.L.Unlock() 54 | } else { 55 | customers_waiting = append(customers_waiting,id) 56 | fmt.Println(id, ": In waiting-room: ", customers_waiting) 57 | barber_available = true 58 | condition.Signal() 59 | condition.L.Unlock() 60 | } 61 | } 62 | 63 | func main() { 64 | go barber() 65 | 66 | time.Sleep(time.Duration(1)*time.Second) 67 | var num_customers = 6 68 | for i := num_customers-1; i >= 0; i-=1 { 69 | go customer(i) 70 | time.Sleep(time.Duration(rand.Intn(3-1)+1)*time.Second) 71 | } 72 | for i:=0;i 0: 23 | id = customers_waiting.pop(0) 24 | mutex.release() 25 | barber_available = 0 26 | cutting_hair(id) 27 | else: 28 | print("Barber: Going to sleep") 29 | while barber_available == 0: 30 | condition.wait() 31 | mutex.release() 32 | print("Barber: Woke up") 33 | 34 | def customer(id): 35 | global barber_available, customers_waiting, mutex, seats 36 | mutex.acquire() 37 | if len(customers_waiting) == seats: 38 | print(id, ": Leaving") 39 | mutex.release() 40 | else: 41 | customers_waiting.append(id) 42 | print(id, ": In waiting-room: ", customers_waiting) 43 | barber_available = 1 44 | condition.notify() 45 | mutex.release() 46 | 47 | if __name__ == "__main__": 48 | b = Thread(target=barber) 49 | b.start() 50 | 51 | sleep(1) 52 | customers = [] 53 | for i in range(6): 54 | c = Thread(target=customer, args=(i,)) 55 | customers.append(c) 56 | while len(customers) > 0: 57 | c = customers.pop() 58 | c.start() 59 | sleep(randint(1,3)) 60 | 61 | 62 | 63 | 64 | --------------------------------------------------------------------------------