.NET(C#):使用安全執行緒集合快速解決生產者消費者問題

來源:互聯網
上載者:User

程式示範:

進入程式,首先得輸入最大容量,比如輸入10:

 

接下來生產線產生了,最初當然只有0個項目,我們現在開始生產5個項目,在“生產數量”中輸入5,如:

 

然後點擊“生產”,5個項目就被生產了:

 

接下來我們再生產12個項目,加上之前的5個項目,此時一共會生產17個項目,但是總容量是10,所以會有7個生產項目要等待(線程阻塞):

 

接著再去生產10個項目,此時已經有7個生產項目在等待狀態,後續的生產項目需求會疊加:

 

現在的情況是:有10個項目已經被生產,還有17個項目等待被生產,下面我們消費5個項目,結果如下:

 

當5個項目被消費後,等待生產的項目立即開始生產,知道容量又一次到最大值10,而左面等待生產的項目個數變成了12(減少了5個)。

下面直接消費100個,結果:

 

由於之前有10個被生產,12個在等待生產,所以等著22個項目被消費後,後續的消費無法滿足,因此有78個消費在等待。

 

最後再生產80個項目,其中78個會被消費,然後剩2個留在生產線上,如:

 

 

生產著消費者問題有非常多的解決方式,不過使用.NET 4.0+的安全執行緒集合解決起來非常簡單。使用者不需要自訂線程同步邏輯,直接使用安全執行緒集合,然後多線程去操作就可以了,當然,更具體些,使用BlockingCollection,它本身不是嚴格意義上的集合,而是包轉另一個安全執行緒集合使他具備阻塞功能。使用BlockingCollection來定義整個生產線集合。接著生產和消費問題就是在這個阻塞集合中進行添加和刪除操作,這裡我們會繼承BlockingCollection得天獨厚的優點,當向已滿的集合中添加值,或者向空集合中刪除值都會造成操作線程阻塞,知道該需求被完成,否則操作線程一直阻塞下去。

 

整個執行上核心就兩個類:Operator和RequestItem。

Operator包含著BlockingCollection,並提供封裝方法來調用BlockingCollection的Add和Take來進行生產和消費操作。

任何操作都被RequestItem來代表,這個類型儲存著操作次數,就是“生產5個項目”中的5。對於可以完成的命令,BlockingCollection顯然不會阻塞,然後根據操作次數執行生產或者消費操作,最後RequestItem會被刪除掉。但是如果命令無法得到滿足,此時BlockCollection會阻塞,相應的RequestItem也會留下,操作次數則代表等待的工作數,同時RequestItem也可以疊加。

 

可以參考:

 

執行上差不多這些,在介面更新上,Operator和RequestItem均繼承INotifyPropertyChanged介面來通知WPF屬性變化,同時生產和消費等待隊列被存到Operator中的ObservableCollection中,有點像MVVM中的ViewModel,但程式沒有用嚴格的MVVM模式來寫。

 

 

Operator類型:

Consumers屬性代表消費等待隊列。

Producers屬性代表生產等待隊列。

Count和Capacity分別代表當前生產線項目個數和總容量。注意由於總容量Capacity不會變因此沒必要像Count屬性那樣進行改變通知。

public ObservableCollection<RequestItem> Consumers { get; private set; }

public ObservableCollection<RequestItem> Producers { get; private set; }

public int Capacity { get; private set; }

 

#region Count

 

private int _Count = 0;

public int Count

{

    get { return _Count; }

    protected set

    {

        if (_Count != value)

        {

            _Count = value;

            OnPropertyChanged("Count");

        }

    }

}

 

RequestItem則更簡單了,只有一個Count屬性代表運算元。

 

最後生產或者消費操作的執行就順水推舟了,我們以生產方法:Produce來樣本(代碼中有注釋):

public void Produce(int count)

{

    //用另一個線程來操作BlockingCollection

    Task.Factory.StartNew(() =>

    {

        //產生RequestItem

        var item = new RequestItem(count);

        //將RequestItem加入到生產等待隊列中

        //UIAction方法是用WPF間接調用WPF Dispatcher的Invoke相關操作

        UIAction(() => Producers.Add(item));

        //嘗試進行生產操作

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

        {

            //調用內部BlockingCollection的Add方法

            blockingQueue.Add(0);

            //重要:此時代碼運行到這說明沒有阻塞,那麼生產成功

            UIAction(() =>

                {

                    //將等待運算元減1

                    --item.Count;

                    //將生產線項目個數加1

                    ++Count;

                });

        }

        //所有生產需求均被完成,將此生產需求從隊列中移除

        UIAction(() => Producers.Remove(item));

    });

}

 

OK,程式整體架構差不多是這樣,還有一些細節和介面上處理就不講了,有需要的話讀者可以參考原始碼。

 

原始碼下載

注意:此為微軟SkyDrive存檔,請用瀏覽器直接下載,用某些下載工具可能無法下載
原始碼環境:Microsoft Visual C# 2010 Express

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.