1. 程式人生 > 其它 >【Go 語言社群】Go語言條件變數的兩個例子

【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;

}