Mirama Khytyn
Mirama Khytyn

Reputation: 1

Why goroutines are going to be deadlocked?

I got these error

fatal error: all goroutines are asleep - deadlock!

`goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000081e0?)
    C:/Program Files/Go/src/runtime/sema.go:71 +0x25
sync.(*WaitGroup).Wait(0x0?)
    C:/Program Files/Go/src/sync/waitgroup.go:118 +0x48
main.main()`

But I use synchronization Wait() and other tools. What wrong? My code:

 package main

    import (
    "fmt"
    "sync"
    )

    func sender(id int, data []int, out chan<- [2]int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < len(data); i += 2 {
        out <- [2]int{data[i], data[i+1]}
    }
    }

    func service(in <-chan [2]int, c, d int, out chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for pair := range in {
        sum := pair[0] + pair[1]
        if sum >= c && sum <= d {
            out <- sum
        }
    }
     }

     func receiver(in <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    line := 1
    for sum := range in {
        fmt.Printf("Line %d: Received sum %d\n", line, sum)
        line++
    }
     }

    func main() {
    data1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    data2 := []int{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
    data3 := []int{21, 22, 23, 24, 25, 26, 27, 28, 29, 30}
    data4 := []int{31, 32, 33, 34, 35, 36, 37, 38, 39, 40}

    c, d := 15, 50

    senderToService := make(chan [2]int, 10)
    serviceToReceiver := make(chan int, 10)

    var wg sync.WaitGroup

    // Start sender goroutines
    wg.Add(4)
    go sender(1, data1, senderToService, &wg)
    go sender(2, data2, senderToService, &wg)
    go sender(3, data3, senderToService, &wg)
    go sender(4, data4, senderToService, &wg)

    // Close senderToService channel once all senders are done
    go func() {
        wg.Wait()
        close(senderToService)
    }()

    // Start service goroutine
    wg.Add(1)
    go service(senderToService, c, d, serviceToReceiver, &wg)

    // Close serviceToReceiver channel once the service is done
    go func() {
        wg.Wait()
        close(serviceToReceiver)
    }()

    // Start receiver goroutine
    wg.Add(1)
    go receiver(serviceToReceiver, &wg)

    // Wait for all goroutines to finish
    wg.Wait()
    }

I am using a single WaitGroup (wg) to manage synchronization across three independent stages of the pipeline: The sender stage produces data. The service stage processes the data. The receiver stage consumes the processed data. When I call wg.Wait() in the main function, it waits for all decrements from all stages The channels senderToService and serviceToReceiver are closed in anonymous goroutines that wait on wg.Wait(). So where is root cause and how to fix it?

Upvotes: -4

Views: 124

Answers (2)

Tomas Vitauvtav
Tomas Vitauvtav

Reputation: 1

#include <iostream>
#include <vector>
#include <omp.h>
#include <mutex>

int main() {
    // Shared array to store computed values
    std::vector<int> shared_array;
    // Mutex to ensure thread-safe access to shared_array
    std::mutex mtx;
    // Total sum variable
    int total_sum = 0;

    // Number of threads
    const int num_threads = 10;

    // Parallel region
    #pragma omp parallel num_threads(num_threads) reduction(+:total_sum)
    {
        // Get thread number (unique identifier for each thread)
        int i = omp_get_thread_num();

        // Compute the value of i^2 + i^3
        int value = i * i + i * i * i;

        // Append the result to the shared array
        {
            std::lock_guard<std::mutex> lock(mtx);
            shared_array.push_back(value);
        }

        // Add the computed value to the total sum
        total_sum += value;
    }

    // Print the contents of the shared array
    std::cout << "Shared array contents: ";
    for (int val : shared_array) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    // Print the total sum
    std::cout << "Total sum: " << total_sum << std::endl;

    return 0;
}

Upvotes: -3

Peter Jean-Pierre
Peter Jean-Pierre

Reputation: 41

The problem is that the application uses a single wait group to wait for three different events (senders done, service done, receiver done). The wait for senders does not complete because the group includes the count for service. The service goroutine does not complete because the program is still waiting on senders. Deadlock!

One fix is to change the program to use three wait groups. A simpler fix is to eliminate unnecessary use of wait groups.

func sender(id int, data []int, out chan<- [2]int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < len(data); i += 2 {
        out <- [2]int{data[i], data[i+1]}
    }
}

func service(in <-chan [2]int, c, d int, out chan<- int) {
    defer close(out)
    for pair := range in {
        sum := pair[0] + pair[1]
        if sum >= c && sum <= d {
            out <- sum
        }
    }
}

func receiver(in <-chan int) {
    line := 1
    for sum := range in {
        fmt.Printf("Line %d: Received sum %d\n", line, sum)
        line++
    }
}

func main() {
    data1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    data2 := []int{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
    data3 := []int{21, 22, 23, 24, 25, 26, 27, 28, 29, 30}
    data4 := []int{31, 32, 33, 34, 35, 36, 37, 38, 39, 40}

    c, d := 15, 50

    senderToService := make(chan [2]int, 10)
    serviceToReceiver := make(chan int, 10)

    var wg sync.WaitGroup

    // Start sender goroutines
    wg.Add(4)
    go sender(1, data1, senderToService, &wg)
    go sender(2, data2, senderToService, &wg)
    go sender(3, data3, senderToService, &wg)
    go sender(4, data4, senderToService, &wg)
    go func() {
        wg.Wait()
        close(senderToService)
    }()

    go service(senderToService, c, d, serviceToReceiver)
    receiver(serviceToReceiver)

}

Upvotes: 4

Related Questions