golang多线程同步

发布时间:2024-11-05 19:25:11

Go是一种新兴的编程语言,由Google开发,旨在简化开发人员构建高效且可靠的软件的工作。它是一种面向并发的语言,内置了用于支持多线程编程的原语。在本文中,我将介绍如何在Go中进行多线程同步,包括锁、条件变量和信号量。

使用互斥锁实现同步

互斥锁是Go语言中最基本的同步机制之一。通过在临界区前后分别调用Lock和Unlock方法,可以确保在同一时间只有一个线程可以进入该临界区。下面是一个示例:

var mutex sync.Mutex var count int func increment() { mutex.Lock() defer mutex.Unlock() count++ } func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() increment() }() } wg.Wait() fmt.Println(count) }

在上面的示例中,我们首先定义了一个全局变量count和一个互斥锁mutex。然后,我们定义了一个increment函数,该函数在进入临界区之前调用Lock方法来获取锁,在离开临界区时调用Unlock方法来释放锁。接下来,我们在main函数中创建了10个goroutine来调用increment函数。最后,我们通过调用Wait方法等待所有的goroutine都执行完毕,并打印出count的值。

使用条件变量实现同步

互斥锁可以确保同一时间只有一个线程进入临界区,但有时我们需要在某个条件为真时才让线程继续执行。这时就可以使用条件变量。下面是一个示例:

var mutex sync.Mutex var cond = sync.NewCond(&mutex) var count int func increment() { mutex.Lock() defer mutex.Unlock() count++ if count == 5 { cond.Broadcast() } } func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() increment() }() } mutex.Lock() cond.Wait() mutex.Unlock() fmt.Println("Condition met") }

在上面的示例中,我们使用了一个条件变量cond来控制线程的执行。在increment函数中,当count的值达到5时,我们调用Broadcast方法通知所有正在等待该条件的线程可以继续执行。在main函数中,我们首先获取互斥锁,然后调用Wait方法进入等待状态,直到该条件为真。当cond.Broadcast()被调用时,线程会被唤醒,继续执行后续代码。

使用信号量实现同步

互斥锁和条件变量提供了基本的同步机制,但有时我们需要更高级的同步原语。信号量是一种经典的同步原语,它可以用来控制对某个资源的访问。下面是一个使用信号量实现生产者-消费者模型的示例:

var empty = make(chan int, 1) var full = make(chan int, 1) var item int func produce() { for i := 0; i < 5; i++ { empty <- i item = i fmt.Println("Produced", item) full <- i } } func consume() { for i := 0; i < 5; i++ { <-full fmt.Println("Consumed", item) <-empty } } func main() { go produce() go consume() time.Sleep(time.Second) }

在上面的示例中,我们使用了两个信号量empty和full来控制生产者和消费者之间的同步。在produce函数中,我们首先把一个空槽empty发送到empty信号量,然后将item设置为当前的生产者值,并打印出该值,最后将一个满槽full发送到full信号量。在consume函数中,我们首先从full信号量接收一个满槽,然后打印出item的值,最后从empty信号量接收一个空槽。通过这种方式,我们可以保证生产者和消费者之间的同步。

相关推荐