【Go 语言社区】Go语言条件变量的两个例子

时间:2022-05-04
本文章向大家介绍【Go 语言社区】Go语言条件变量的两个例子,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在Go语言中 sync.Cond 代表条件变量,但它需要配置锁才能有用.

var m Mutex

c := NewCond(&m)

或 c := sync.NewCond(&sync.RWMutex{}) 之类. 它有三个函数: wait/signal/broadcast 望文知义,和Windows下的InitializeConditionVariable与WaitForSingleObject()之类, 及Linux下的pthread_cond_t等作用差不多.

弄了两个例子:

/*

条件变量 Cond 例子



Author: xcl

Date: 2015-11-29

*/



package main



import (

        "fmt"

        "runtime"

        "sync"

        "time"

)



func main() {



        runtime.GOMAXPROCS(4)



        test333()

}



func testCond() {



        c := sync.NewCond(&sync.Mutex{})

        condition := false



        go func() {

                time.Sleep(time.Second * 1)

                c.L.Lock()

                fmt.Println("[1] 变更condition状态,并发出变更通知.")

                condition = true

                c.Signal() //c.Broadcast()

                fmt.Println("[1] 继续后续处理.")

                c.L.Unlock()



        }()



        c.L.Lock()

        fmt.Println("[2] condition..........1")

        for !condition {

                fmt.Println("[2] condition..........2")

                //等待Cond消息通知

                c.Wait()

                fmt.Println("[2] condition..........3")

        }

        fmt.Println("[2] condition..........4")

        c.L.Unlock()



        fmt.Println("main end...")

}



/*



testCond()运行结果:



[2] condition..........1

[2] condition..........2

[1] 变更condition状态,并发出变更通知.

[1] 继续后续处理.

[2] condition..........3

[2] condition..........4

main end...





*/

复制代码

例二

/*

条件变量 Cond 例子



Author: xcl

Date: 2015-11-29

*/



package main



import (

        "fmt"

        "runtime"

        "sync"

        "time"

)



const MAX_CLIENTS = 3



func main() {

        runtime.GOMAXPROCS(4)



        testCond()

}



func testCond() {

        s := NewServer()

        go s.IOloop()



        time.Sleep(time.Second * 1)

        go func() {

                s.Release()

        }()



        go func() {

                s.Release()

        }()



        time.Sleep(time.Second * 1)

        s.Release()

        time.Sleep(time.Second * 1)

        fmt.Println("[testCond] end.")

}



type Server struct {

        clients uint64

        cond    *sync.Cond

}



func NewServer() *Server {

        s := &Server{}

        s.cond = sync.NewCond(&sync.Mutex{})

        return s

}



func (s *Server) IOloop() {

        for {

                s.cond.L.Lock()

                for s.clients == MAX_CLIENTS {

                        fmt.Println("[IOloop] 等于MAX_CLIENTS了,等待Cond通知.即有触发Release()")

                        s.cond.Wait()

                }

                s.cond.L.Unlock()

                s.clients++

                fmt.Println("[IOloop] clients:", s.clients)

        }

}



func (s *Server) Release() {

        s.cond.L.Lock()

        s.clients--

        fmt.Println("[Release] a clients:", s.clients)

        s.cond.Signal()

        fmt.Println("[Release] b clients:", s.clients)

        s.cond.L.Unlock()



}



/*

运行结果:



[IOloop] clients: 1

[IOloop] clients: 2

[IOloop] clients: 3

[IOloop] 等于MAX_CLIENTS了,等待Cond通知.即有触发Release()

[Release] a clients: 2

[Release] b clients: 2

[Release] a clients: 1

[Release] b clients: 1

[IOloop] clients: 2

[IOloop] clients: 3

[IOloop] 等于MAX_CLIENTS了,等待Cond通知.即有触发Release()

[Release] a clients: 2

[Release] b clients: 2

[IOloop] clients: 3

[IOloop] 等于MAX_CLIENTS了,等待Cond通知.即有触发Release()

[testCond] end.



*/

对于条件变量和channl,知乎有个问答很精彩,可以看看: http://www.zhihu.com/question/27256570

另外 <<Go语言并发编程>>中也有个同一时间多个Goroutine分别进行对一个文件进行读写操作的例子也很精彩,直观。

噢,对了,附上C++11条件变量的使用例子:

// condition_variable example

#include <iostream>           // std::cout

#include <thread>             // std::thread

#include <mutex>              // std::mutex, std::unique_lock

#include <condition_variable> // std::condition_variable



std::mutex mtx;

std::condition_variable cv;

bool ready = false;



void print_id (int id) {

  std::unique_lock<std::mutex> lck(mtx);

  while (!ready) cv.wait(lck);

  // ...

  std::cout << "thread " << id << 'n';

}



void go() {

  std::unique_lock<std::mutex> lck(mtx);

  ready = true;

  cv.notify_all();

}



int main ()

{

  std::thread threads[10];

  // spawn 10 threads:

  for (int i=0; i<10; ++i)

    threads[i] = std::thread(print_id,i);



  std::cout << "10 threads ready to race...n";

  go();                       // go!



  for (auto& th : threads) th.join();



  return 0;

}