Sling Academy
Home/Golang/Using `sync.Cond` for Conditional Synchronization in Go

Using `sync.Cond` for Conditional Synchronization in Go

Last updated: November 27, 2024

Go, also known as Golang, provides robust concurrency primitives. One of these is the sync.Cond type, which is used to synchronize Goroutines in situations requiring conditional execution. In this article, we will dive into using sync.Cond for coordinating concurrent routines.

Understanding sync.Cond

The sync.Cond is a structure that uses condition variables to enable Goroutines to wait for or broadcast notifications. It wraps around a sync.Locker interface—a common choice is usually sync.Mutex—to provide safely synchronized access to shared variables.

Basic Syntax


import (
    "sync"
)

var mu sync.Mutex
var cond = sync.NewCond(&mu)

This sets up a condition variable named cond that will manage coordination using the mu mutex.

Usability

Let’s look at some common operations provided by sync.Cond:

  • Wait: Block the Goroutine until notified. It releases the associated mutex, then re-acquires it when the Goroutine is awakened.

    
    mu.Lock()
    for condition != fulfilled {
        cond.Wait()
    }
    // Proceed with the condition fulfilled
    mu.Unlock()
        
  • Signal: Wakes up a single Goroutine waiting on cond. It is used when only one Goroutine needs to be resumed.

    
    cond.Signal()
        
  • Broadcast: Wakes up all Goroutines waiting on cond. Useful when multiple Goroutines need to be resumed at once.

    
    cond.Broadcast()
        

An Example of sync.Cond Operation

Here is a simplified example demonstrating a producer-consumer problem where multiple consumers wait for the producer to add an item to a shared resource:


package main

import (
    "fmt"
    "sync"
)

var (
    mu    sync.Mutex
    cond  = sync.NewCond(&mu)
    queue []int
)

func produce(item int) {
    mu.Lock()
    queue = append(queue, item)
    fmt.Println("Produced:", item)
    cond.Signal()  // Notify one waiting consumer
    mu.Unlock()
}

func consume() {
    mu.Lock()
    for len(queue) == 0 {
        cond.Wait()
    }
    item := queue[0]
    queue = queue[1:]
    fmt.Println("Consumed:", item)
    mu.Unlock()
}

func main() {
    for i := 0; i < 5; i++ {
        go consume()
    }

    for i := 0; i < 5; i++ {
        produce(i)
    }
}

In this code, several consumer Goroutines are waiting for the produce function to insert items into a queue. Once an item is produced, a consumer is notified and processes the item.

Conclusion

Using sync.Cond in Go can simplify complex synchronization issues involving conditional waiting. It's particularly useful for structuring scenarios where multiple Goroutines need to wait for a certain condition to be met before proceeding. Understanding how to implement and manage these variables is critical for efficient concurrent programming in Go.

Next Article: The Power of Goroutine Stacks: How Go Optimizes Memory

Previous Article: Dynamic Worker Pool Implementation in Go

Series: Concurrency and Synchronization in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant