日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

C# 多线程控制 通讯 和切换

發(fā)布時(shí)間:2023/12/10 C# 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 多线程控制 通讯 和切换 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

.多線程的概念?

  Windows是一個(gè)多任務(wù)的系統(tǒng),如果你使用的是windows 2000及其以上版本,你可以通過(guò)任務(wù)管理器查看當(dāng)前系統(tǒng)運(yùn)行的程序和進(jìn)程。什么是進(jìn)程呢?當(dāng)一個(gè)程序開(kāi)始運(yùn)行時(shí),它就是一個(gè)進(jìn)程,進(jìn)程所指包括運(yùn)行中的程序和程序所使用到的內(nèi)存和系統(tǒng)資源。而一個(gè)進(jìn)程又是由多個(gè)線程所組成的,線程是程序中的一個(gè)執(zhí)行流,每個(gè)線程都有自己的專有寄存器(棧指針、程序計(jì)數(shù)器等),但代碼區(qū)是共享的,即不同的線程可以執(zhí)行同樣的函數(shù)。多線程是指程序中包含多個(gè)執(zhí)行流,即在一個(gè)程序中可以同時(shí)運(yùn)行多個(gè)不同的線程來(lái)執(zhí)行不同的任務(wù),也就是說(shuō)允許單個(gè)程序創(chuàng)建多個(gè)并行執(zhí)行的線程來(lái)完成各自的任務(wù)。瀏覽器就是一個(gè)很好的多線程的例子,在瀏覽器中你可以在下載JAVA小應(yīng)用程序或圖象的同時(shí)滾動(dòng)頁(yè)面,在訪問(wèn)新頁(yè)面時(shí),播放動(dòng)畫(huà)和聲音,打印文件等。?

  多線程的好處在于可以提高CPU的利用率——任何一個(gè)程序員都不希望自己的程序很多時(shí)候沒(méi)事可干,在多線程程序中,一個(gè)線程必須等待的時(shí)候,CPU可以運(yùn)行其它的線程而不是等待,這樣就大大提高了程序的效率。?

  然而我們也必須認(rèn)識(shí)到線程本身可能影響系統(tǒng)性能的不利方面,以正確使用線程:

  • 線程也是程序,所以線程需要占用內(nèi)存,線程越多占用內(nèi)存也越多
  • 多線程需要協(xié)調(diào)和管理,所以需要CPU時(shí)間跟蹤線程
  • 線程之間對(duì)共享資源的訪問(wèn)會(huì)相互影響,必須解決競(jìng)用共享資源的問(wèn)題
  • 線程太多會(huì)導(dǎo)致控制太復(fù)雜,最終可能造成很多Bug

  基于以上認(rèn)識(shí),我們可以一個(gè)比喻來(lái)加深理解。假設(shè)有一個(gè)公司,公司里有很多各司其職的職員,那么我們可以認(rèn)為這個(gè)正常運(yùn)作的公司就是一個(gè)進(jìn)程,而公司里的職員就是線程。一個(gè)公司至少得有一個(gè)職員吧,同理,一個(gè)進(jìn)程至少包含一個(gè)線程。在公司里,你可以一個(gè)職員干所有的事,但是效率很顯然是高不起來(lái)的,一個(gè)人的公司也不可能做大;一個(gè)程序中也可以只用一個(gè)線程去做事,事實(shí)上,一些過(guò)時(shí)的語(yǔ)言如fortune,basic都是如此,但是象一個(gè)人的公司一樣,效率很低,如果做大程序,效率更低——事實(shí)上現(xiàn)在幾乎沒(méi)有單線程的商業(yè)軟件。公司的職員越多,老板就得發(fā)越多的薪水給他們,還得耗費(fèi)大量精力去管理他們,協(xié)調(diào)他們之間的矛盾和利益;程序也是如此,線程越多耗費(fèi)的資源也越多,需要CPU時(shí)間去跟蹤線程,還得解決諸如死鎖,同步等問(wèn)題。總之,如果你不想你的公司被稱為“皮包公司”,你就得多幾個(gè)員工;如果你不想讓你的程序顯得稚氣,就在你的程序里引入多線程吧!?

  本文將對(duì)C#編程中的多線程機(jī)制進(jìn)行探討,通過(guò)一些實(shí)例解決對(duì)線程的控制,多線程間通訊等問(wèn)題。為了省去創(chuàng)建GUI那些繁瑣的步驟,更清晰地逼近線程的本質(zhì),下面所有的程序都是控制臺(tái)程序,程序最后的Console.ReadLine()是為了使程序中途停下來(lái),以便看清楚執(zhí)行過(guò)程中的輸出。?

  好了,廢話少說(shuō),讓我們來(lái)體驗(yàn)一下多線程的C#吧!?

  二.操縱一個(gè)線程?

  任何程序在執(zhí)行時(shí),至少有一個(gè)主線程,下面這段小程序可以給讀者一個(gè)直觀的印象:

//SystemThread.cs using System; using System.Threading; namespace ThreadTest {class RunIt{[STAThread]static void Main(string[] args){Thread.CurrentThread.Name="System Thread";//給當(dāng)前線程起名為"System Thread" Console.WriteLine(Thread.CurrentThread.Name+"'Status:"+Thread.CurrentThread.ThreadState);Console.ReadLine();}} }

編譯執(zhí)行后你看到了什么?是的,程序?qū)a(chǎn)生如下輸出:?

  System Thread's Status:Running?

  在這里,我們通過(guò)Thread類的靜態(tài)屬性CurrentThread獲取了當(dāng)前執(zhí)行的線程,對(duì)其Name屬性賦值“System Thread”,最后還輸出了它的當(dāng)前狀態(tài)(ThreadState)。所謂靜態(tài)屬性,就是這個(gè)類所有對(duì)象所公有的屬性,不管你創(chuàng)建了多少個(gè)這個(gè)類的實(shí)例,但是類的靜態(tài)屬性在內(nèi)存中只有一個(gè)。很容易理解CurrentThread為什么是靜態(tài)的——雖然有多個(gè)線程同時(shí)存在,但是在某一個(gè)時(shí)刻,CPU只能執(zhí)行其中一個(gè)。?

  就像上面程序所演示的,我們通過(guò)Thread類來(lái)創(chuàng)建和控制線程。注意到程序的頭部,我們使用了如下命名空間:

  using System;
  using System.Threading;


  在.net framework class library中,所有與多線程機(jī)制應(yīng)用相關(guān)的類都是放在System.Threading命名空間中的。其中提供Thread類用于創(chuàng)建線程,ThreadPool類用于管理線程池等等,此外還提供解決了線程執(zhí)行安排,死鎖,線程間通訊等實(shí)際問(wèn)題的機(jī)制。如果你想在你的應(yīng)用程序中使用多線程,就必須包含這個(gè)類。Thread類有幾個(gè)至關(guān)重要的方法,描述如下:

  • Start():啟動(dòng)線程
  • Sleep(int):靜態(tài)方法,暫停當(dāng)前線程指定的毫秒數(shù)
  • Abort():通常使用該方法來(lái)終止一個(gè)線程
  • Suspend():該方法并不終止未完成的線程,它僅僅掛起線程,以后還可恢復(fù)。
  • Resume():恢復(fù)被Suspend()方法掛起的線程的執(zhí)行

1

下面我們就動(dòng)手來(lái)創(chuàng)建一個(gè)線程,使用Thread類創(chuàng)建線程時(shí),只需提供線程入口即可。線程入口使程序知道該讓這個(gè)線程干什么事,在C#中,線程入口是通過(guò)ThreadStart代理(delegate)來(lái)提供的,你可以把ThreadStart理解為一個(gè)函數(shù)指針,指向線程要執(zhí)行的函數(shù),當(dāng)調(diào)用Thread.Start()方法后,線程就開(kāi)始執(zhí)行ThreadStart所代表或者說(shuō)指向的函數(shù)。?

  打開(kāi)你的VS.net,新建一個(gè)控制臺(tái)應(yīng)用程序(Console Application),下面這些代碼將讓你體味到完全控制一個(gè)線程的無(wú)窮樂(lè)趣!

  //ThreadTest.cs using System;using System.Threading; namespace ThreadTest{public class Alpha{public void Beta(){while (true){Console.WriteLine("Alpha.Beta is running in its own thread.");}}}; public class Simple{public static int Main(){Console.WriteLine("Thread Start/Stop/Join Sample");Alpha oAlpha = new Alpha();file://這里創(chuàng)建一個(gè)線程,使之執(zhí)行Alpha類的Beta()方法Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));oThread.Start();while (!oThread.IsAlive);Thread.Sleep(1);oThread.Abort();oThread.Join();Console.WriteLine();Console.WriteLine("Alpha.Beta has finished"); try {Console.WriteLine("Try to restart the Alpha.Beta thread");oThread.Start();}catch (ThreadStateException) {Console.Write("ThreadStateException trying to restart Alpha.Beta. ");Console.WriteLine("Expected since aborted threads cannot be restarted.");Console.ReadLine();}return 0;}}}

  這段程序包含兩個(gè)類AlphaSimple,在創(chuàng)建線程oThread時(shí)我們用指向Alpha.Beta()方法的初始化了ThreadStart代理(delegate)對(duì)象,當(dāng)我們創(chuàng)建的線程oThread調(diào)用oThread.Start()方法啟動(dòng)時(shí),實(shí)際上程序運(yùn)行的是Alpha.Beta()方法:

  Alpha oAlpha = new Alpha();Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));oThread.Start();

然后在Main()函數(shù)的while循環(huán)中,我們使用靜態(tài)方法Thread.Sleep()讓主線程停了1ms,這段時(shí)間CPU轉(zhuǎn)向執(zhí)行線程oThread。然后我們?cè)噲D用Thread.Abort()方法終止線程oThread,注意后面的oThread.Join()Thread.Join()方法使主線程等待,直到oThread線程結(jié)束。你可以給Thread.Join()方法指定一個(gè)int型的參數(shù)作為等待的最長(zhǎng)時(shí)間。之后,我們?cè)噲D用Thread.Start()方法重新啟動(dòng)線程oThread,但是顯然Abort()方法帶來(lái)的后果是不可恢復(fù)的終止線程,所以最后程序會(huì)拋出ThreadStateException異常。?

  程序最后得到的結(jié)果將如下圖:

?

在這里我們要注意的是其它線程都是依附于Main()函數(shù)所在的線程的,Main()函數(shù)是C#程序的入口,起始線程可以稱之為主線程,如果所有的前臺(tái)線程都停止了,那么主線程可以終止,而所有的后臺(tái)線程都將無(wú)條件終止。而所有的線程雖然在微觀上是串行執(zhí)行的,但是在宏觀上你完全可以認(rèn)為它們?cè)诓⑿袌?zhí)行。?

  讀者一定注意到了Thread.ThreadState這個(gè)屬性,這個(gè)屬性代表了線程運(yùn)行時(shí)狀態(tài),在不同的情況下有不同的值,于是我們有時(shí)候可以通過(guò)對(duì)該值的判斷來(lái)設(shè)計(jì)程序流程。ThreadState在各種情況下的可能取值如下:

  • Aborted:線程已停止
  • AbortRequested:線程的Thread.Abort()方法已被調(diào)用,但是線程還未停止
  • Background:線程在后臺(tái)執(zhí)行,與屬性Thread.IsBackground有關(guān)
  • Running:線程正在正常運(yùn)行
  • Stopped:線程已經(jīng)被停止
  • StopRequested:線程正在被要求停止
  • Suspended:線程已經(jīng)被掛起(此狀態(tài)下,可以通過(guò)調(diào)用Resume()方法重新運(yùn)行)
  • SuspendRequested:線程正在要求被掛起,但是未來(lái)得及響應(yīng)
  • Unstarted:未調(diào)用Thread.Start()開(kāi)始線程的運(yùn)行
  • WaitSleepJoin:線程因?yàn)檎{(diào)用了Wait(),Sleep()或Join()等方法處于封鎖狀態(tài)

  上面提到了Background狀態(tài)表示該線程在后臺(tái)運(yùn)行,那么后臺(tái)運(yùn)行的線程有什么特別的地方呢?其實(shí)后臺(tái)線程跟前臺(tái)線程只有一個(gè)區(qū)別,那就是后臺(tái)線程不妨礙程序的終止。一旦一個(gè)進(jìn)程所有的前臺(tái)線程都終止后,CLR(通用語(yǔ)言運(yùn)行環(huán)境)將通過(guò)調(diào)用任意一個(gè)存活中的后臺(tái)進(jìn)程的Abort()方法來(lái)徹底終止進(jìn)程。?

  當(dāng)線程之間爭(zhēng)奪CPU時(shí)間時(shí),CPU按照是線程的優(yōu)先級(jí)給予服務(wù)的。在C#應(yīng)用程序中,用戶可以設(shè)定5個(gè)不同的優(yōu)先級(jí),由高到低分別是Highest,AboveNormal,Normal,BelowNormal,Lowest,在創(chuàng)建線程時(shí)如果不指定優(yōu)先級(jí),那么系統(tǒng)默認(rèn)為ThreadPriority.Normal。給一個(gè)線程指定優(yōu)先級(jí)
,我們可以使用如下代碼:

  //設(shè)定優(yōu)先級(jí)為最低myThread.Priority=ThreadPriority.Lowest;

  通過(guò)設(shè)定線程的優(yōu)先級(jí),我們可以安排一些相對(duì)重要的線程優(yōu)先執(zhí)行,例如對(duì)用戶的響應(yīng)等等。?

  現(xiàn)在我們對(duì)怎樣創(chuàng)建和控制一個(gè)線程已經(jīng)有了一個(gè)初步的了解,下面我們將深入研究線程實(shí)現(xiàn)中比較典型的的問(wèn)題,并且探討其解決方法。?

  三.線程的同步和通訊——生產(chǎn)者和消費(fèi)者?

  假設(shè)這樣一種情況,兩個(gè)線程同時(shí)維護(hù)一個(gè)隊(duì)列,如果一個(gè)線程對(duì)隊(duì)列中添加元素,而另外一個(gè)線程從隊(duì)列中取用元素,那么我們稱添加元素的線程為生產(chǎn)者,稱取用元素的線程為消費(fèi)者。生產(chǎn)者與消費(fèi)者問(wèn)題看起來(lái)很簡(jiǎn)單,但是卻是多線程應(yīng)用中一個(gè)必須解決的問(wèn)題,它涉及到線程之間的同步和通訊問(wèn)題。?

  前面說(shuō)過(guò),每個(gè)線程都有自己的資源,但是代碼區(qū)是共享的,即每個(gè)線程都可以執(zhí)行相同的函數(shù)。但是多線程環(huán)境下,可能帶來(lái)的問(wèn)題就是幾個(gè)線程同時(shí)執(zhí)行一個(gè)函數(shù),導(dǎo)致數(shù)據(jù)的混亂,產(chǎn)生不可預(yù)料的結(jié)果,因此我們必須避免這種情況的發(fā)生。C#提供了一個(gè)關(guān)鍵字lock,它可以把一段代碼定義為互斥段(critical section),互斥段在一個(gè)時(shí)刻內(nèi)只允許一個(gè)線程進(jìn)入執(zhí)行,而其他線程必須等待。在C#中,關(guān)鍵字lock定義如下:

lock(expression) statement_block

expression代表你希望跟蹤的對(duì)象,通常是對(duì)象引用。一般地,如果你想保護(hù)一個(gè)類的實(shí)例,你可以使用this;如果你希望保護(hù)一個(gè)靜態(tài)變量(如互斥代碼段在一個(gè)靜態(tài)方法內(nèi)部),一般使用類名就可以了。而statement_block就是互斥段的代碼,這段代碼在一個(gè)時(shí)刻內(nèi)只可能被一個(gè)線程執(zhí)行。?

  下面是一個(gè)使用lock關(guān)鍵字的典型例子,我將在注釋里向大家說(shuō)明lock關(guān)鍵字的用法和用途:

  //lock.csusing System;using System.Threading; internal class Account {int balance;Random r = new Random();internal Account(int initial) {balance = initial;} internal int Withdraw(int amount) {if (balance < 0) {file://如果balance小于0則拋出異常throw new Exception("Negative Balance");}//下面的代碼保證在當(dāng)前線程修改balance的值完成之前//不會(huì)有其他線程也執(zhí)行這段代碼來(lái)修改balance的值//因此,balance的值是不可能小于0的lock (this){Console.WriteLine("Current Thread:"+Thread.CurrentThread.Name);file://如果沒(méi)有l(wèi)ock關(guān)鍵字的保護(hù),那么可能在執(zhí)行完if的條件判斷之后file://另外一個(gè)線程卻執(zhí)行了balance=balance-amount修改了balance的值file://而這個(gè)修改對(duì)這個(gè)線程是不可見(jiàn)的,所以可能導(dǎo)致這時(shí)if的條件已經(jīng)不成立了file://但是,這個(gè)線程卻繼續(xù)執(zhí)行balance=balance-amount,所以導(dǎo)致balance可能小于0if (balance >= amount) {Thread.Sleep(5);balance = balance - amount;return amount;} else {return 0; // transaction rejected     }}}internal void DoTransactions() {for (int i = 0; i < 100; i++) Withdraw(r.Next(-50, 100));}} internal class Test {static internal Thread[] threads = new Thread[10];public static void Main() {Account acc = new Account (0);for (int i = 0; i < 10; i++) {Thread t = new Thread(new ThreadStart(acc.DoTransactions));threads[i] = t;}for (int i = 0; i < 10; i++) threads[i].Name=i.ToString();for (int i = 0; i < 10; i++) threads[i].Start();Console.ReadLine();}}

  而多線程公用一個(gè)對(duì)象時(shí),也會(huì)出現(xiàn)和公用代碼類似的問(wèn)題,這種問(wèn)題就不應(yīng)該使用lock關(guān)鍵字了,這里需要用到System.Threading中的一個(gè)類Monitor,我們可以稱之為監(jiān)視器,Monitor提供了使線程共享資源的方案。?

  Monitor類可以鎖定一個(gè)對(duì)象,一個(gè)線程只有得到這把鎖才可以對(duì)該對(duì)象進(jìn)行操作。對(duì)象鎖機(jī)制保證了在可能引起混亂的情況下一個(gè)時(shí)刻只有一個(gè)線程可以訪問(wèn)這個(gè)對(duì)象。Monitor必須和一個(gè)具體的對(duì)象相關(guān)聯(lián),但是由于它是一個(gè)靜態(tài)的類,所以不能使用它來(lái)定義對(duì)象,而且它的所有方法都是靜態(tài)的,不能使用對(duì)象來(lái)引用。下面代碼說(shuō)明了使用Monitor鎖定一個(gè)對(duì)象的情形:

  ......Queue oQueue=new Queue();......Monitor.Enter(oQueue);......//現(xiàn)在oQueue對(duì)象只能被當(dāng)前線程操縱了Monitor.Exit(oQueue);//釋放鎖

  如上所示,當(dāng)一個(gè)線程調(diào)用Monitor.Enter()方法鎖定一個(gè)對(duì)象時(shí),這個(gè)對(duì)象就歸它所有了,其它線程想要訪問(wèn)這個(gè)對(duì)象,只有等待它使用Monitor.Exit()方法釋放鎖。為了保證線程最終都能釋放鎖,你可以把Monitor.Exit()方法寫在try-catch-finally結(jié)構(gòu)中的finally代碼塊里。對(duì)于任何一個(gè)被Monitor鎖定的對(duì)象,內(nèi)存中都保存著與它相關(guān)的一些信息,其一是現(xiàn)在持有鎖的線程的引用,其二是一個(gè)預(yù)備隊(duì)列,隊(duì)列中保存了已經(jīng)準(zhǔn)備好獲取鎖的線程,其三是一個(gè)等待隊(duì)列,隊(duì)列中保存著當(dāng)前正在等待這個(gè)對(duì)象狀態(tài)改變的隊(duì)列的引用。當(dāng)擁有對(duì)象鎖的線程準(zhǔn)備釋放鎖時(shí),它使用Monitor.Pulse()方法通知等待隊(duì)列中的第一個(gè)線程,于是該線程被轉(zhuǎn)移到預(yù)備隊(duì)列中,當(dāng)對(duì)象鎖被釋放時(shí),在預(yù)備隊(duì)列中的線程可以立即獲得對(duì)象鎖。?

  下面是一個(gè)展示如何使用lock關(guān)鍵字和Monitor類來(lái)實(shí)現(xiàn)線程的同步和通訊的例子,也是一個(gè)典型的生產(chǎn)者與消費(fèi)者問(wèn)題。這個(gè)例程中,生產(chǎn)者線程和消費(fèi)者線程是交替進(jìn)行的,生產(chǎn)者寫入一個(gè)數(shù),消費(fèi)者立即讀取并且顯示,我將在注釋中介紹該程序的精要所在。用到的系統(tǒng)命名空間如下:

  using System;using System.Threading;

首先,我們定義一個(gè)被操作的對(duì)象的類Cell,在這個(gè)類里,有兩個(gè)方法:ReadFromCell()WriteToCell。消費(fèi)者線程將調(diào)用ReadFromCell()讀取cellContents的內(nèi)容并且顯示出來(lái),生產(chǎn)者進(jìn)程將調(diào)用WriteToCell()方法向cellContents寫入數(shù)據(jù)。

  public class Cell{int cellContents; // Cell對(duì)象里邊的內(nèi)容bool readerFlag = false; // 狀態(tài)標(biāo)志,為true時(shí)可以讀取,為false則正在寫入public int ReadFromCell( ){lock(this) // Lock關(guān)鍵字保證了什么,請(qǐng)大家看前面對(duì)lock的介紹     {if (!readerFlag)//如果現(xiàn)在不可讀取     { try{file://等待WriteToCell方法中調(diào)用Monitor.Pulse()方法Monitor.Wait(this);}catch (SynchronizationLockException e){Console.WriteLine(e);}catch (ThreadInterruptedException e){Console.WriteLine(e);}}Console.WriteLine("Consume: {0}",cellContents);readerFlag = false; file://重置readerFlag標(biāo)志,表示消費(fèi)行為已經(jīng)完成Monitor.Pulse(this); file://通知WriteToCell()方法(該方法在另外一個(gè)線程中執(zhí)行,等待中)     }return cellContents;}public void WriteToCell(int n){lock(this){if (readerFlag){try{Monitor.Wait(this);}catch (SynchronizationLockException e){file://當(dāng)同步方法(指Monitor類除Enter之外的方法)在非同步的代碼區(qū)被調(diào)用       Console.WriteLine(e);}catch (ThreadInterruptedException e){file://當(dāng)線程在等待狀態(tài)的時(shí)候中止       Console.WriteLine(e);}}cellContents = n;Console.WriteLine("Produce: {0}",cellContents);readerFlag = true; Monitor.Pulse(this); file://通知另外一個(gè)線程中正在等待的ReadFromCell()方法     }}}

  下面定義生產(chǎn)者CellProd和消費(fèi)者類CellCons,它們都只有一個(gè)方法ThreadRun(),以便在Main()函數(shù)中提供給線程的ThreadStart代理對(duì)象,作為線程的入口。

  public class CellProd{Cell cell; // 被操作的Cell對(duì)象int quantity = 1; // 生產(chǎn)者生產(chǎn)次數(shù),初始化為1 public CellProd(Cell box, int request){//構(gòu)造函數(shù)cell = box; quantity = request; }public void ThreadRun( ){for(int looper=1; looper<=quantity; looper++)cell.WriteToCell(looper); file://生產(chǎn)者向操作對(duì)象寫入信息   }} public class CellCons{Cell cell; int quantity = 1; public CellCons(Cell box, int request){cell = box; quantity = request; }public void ThreadRun( ){int valReturned;for(int looper=1; looper<=quantity; looper++)valReturned=cell.ReadFromCell( );//消費(fèi)者從操作對(duì)象中讀取信息   }}

  然后在下面這個(gè)類MonitorSampleMain()函數(shù)中我們要做的就是創(chuàng)建兩個(gè)線程分別作為生產(chǎn)者和消費(fèi)者,使用CellProd.ThreadRun()方法和CellCons.ThreadRun()方法對(duì)同一個(gè)Cell對(duì)象進(jìn)行操作。

  public class MonitorSample{public static void Main(String[] args){int result = 0; file://一個(gè)標(biāo)志位,如果是0表示程序沒(méi)有出錯(cuò),如果是1表明有錯(cuò)誤發(fā)生Cell cell = new Cell( ); //下面使用cell初始化CellProd和CellCons兩個(gè)類,生產(chǎn)和消費(fèi)次數(shù)均為20次CellProd prod = new CellProd(cell, 20); CellCons cons = new CellCons(cell, 20); Thread producer = new Thread(new ThreadStart(prod.ThreadRun));Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));//生產(chǎn)者線程和消費(fèi)者線程都已經(jīng)被創(chuàng)建,但是沒(méi)有開(kāi)始執(zhí)行 try{producer.Start( );consumer.Start( ); producer.Join( ); consumer.Join( );Console.ReadLine();}catch (ThreadStateException e){file://當(dāng)線程因?yàn)樗帬顟B(tài)的原因而不能執(zhí)行被請(qǐng)求的操作     Console.WriteLine(e); result = 1; }catch (ThreadInterruptedException e){file://當(dāng)線程在等待狀態(tài)的時(shí)候中止     Console.WriteLine(e); result = 1; }//盡管Main()函數(shù)沒(méi)有返回值,但下面這條語(yǔ)句可以向父進(jìn)程返回執(zhí)行結(jié)果Environment.ExitCode = result;}}

  大家可以看到,在上面的例程中,同步是通過(guò)等待Monitor.Pulse()來(lái)完成的。首先生產(chǎn)者生產(chǎn)了一個(gè)值,而同一時(shí)刻消費(fèi)者處于等待狀態(tài),直到收到生產(chǎn)者的脈沖(Pulse)”通知它生產(chǎn)已經(jīng)完成,此后消費(fèi)者進(jìn)入消費(fèi)狀態(tài),而生產(chǎn)者開(kāi)始等待消費(fèi)者完成操作后將調(diào)用Monitor.Pulese()發(fā)出的脈沖。它的執(zhí)行結(jié)果很簡(jiǎn)單:

  Produce: 1
  Consume: 1
  Produce: 2
  Consume: 2
  Produce: 3
  Consume: 3
  ...
  ...
  Produce: 20
  Consume: 20

  事實(shí)上,這個(gè)簡(jiǎn)單的例子已經(jīng)幫助我們解決了多線程應(yīng)用程序中可能出現(xiàn)的大問(wèn)題,只要領(lǐng)悟了解決線程間沖突的基本方法,很容易把它應(yīng)用到比較復(fù)雜的程序中去。

?

關(guān)于JOIN()的一點(diǎn)理解

?? ? Thread.Join()在MSDN中的解釋很模糊:Blocks the calling thread until a thread terminates

有兩個(gè)主要問(wèn)題:1.什么是the calling thread?

? ? ? ? ? ? ? ? ? ???? 2.什么是a thread??

?

? ? ?? 首先來(lái)看一下有關(guān)的概念: 我們執(zhí)行一個(gè).exe文件實(shí)際上就是開(kāi)啟了一個(gè)進(jìn)程,同時(shí)開(kāi)啟了至少一個(gè)線程,

但是真正干活的是線程,就好比一個(gè)Team有好幾個(gè)人,但是真正干活的是人不是Team.?

????? 具體到代碼來(lái)說(shuō),以Console Application為例:程序Test.exe從Main函數(shù)開(kāi)始運(yùn)行,實(shí)際上是有一個(gè)線程

在執(zhí)行Main函數(shù),我們稱作MainThread.假如我們?cè)贛ain函數(shù)中聲明了一個(gè)Thread,稱作NewThread,并且調(diào)用了

NewThread.Start()的方法,那么 MainThread在處理Main函數(shù)里面的代碼時(shí)遇到NewThread.Start()時(shí),就會(huì)

去調(diào)用NewThread.

? ? ?? 基于上面的討論,我們可以得出結(jié)論:在我們剛才的例子中the calling thread就是MainThread,而a thread

指的洽洽就是MainThread調(diào)用的NewThread線程。?

?????? 現(xiàn)在回到MSDN的解釋,我們可以這么翻譯:當(dāng)NewThread調(diào)用Join方法的時(shí)候,MainThread就被停止執(zhí)行,

直到NewThread線程執(zhí)行完畢。這樣就好理解了吧O(∩_∩)O哈哈~?

?

? ? ?? 好了,前面分析完了,現(xiàn)在來(lái)看測(cè)試用例吧:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading;namespace Test {class TestThread{private static void ThreadFuncOne(){for (int i = 0; i < 10; i++){Console.WriteLine(Thread.CurrentThread.Name +" i = " + i);}Console.WriteLine(Thread.CurrentThread.Name + " has finished");}static void Main(string[] args){Thread.CurrentThread.Name = "MainThread";Thread newThread = new Thread(new ThreadStart(TestThread.ThreadFuncOne));newThread.Name = "NewThread";for (int j = 0; j < 20; j++){if (j == 10){newThread.Start();newThread.Join();}else{Console.WriteLine(Thread.CurrentThread.Name + " j = " + j);}}Console.Read();}} }

下面是測(cè)試的結(jié)果:

?

  結(jié)論:從測(cè)試中我們可以很清楚的看到MainThread在NewThread.Join被調(diào)用后被阻塞,直到NewThread

執(zhí)行完畢才繼續(xù)執(zhí)行。

?

關(guān)于 Monitor.Wait()和Pulse()的知識(shí)

1.Monitor.Wait方法
當(dāng)線程調(diào)用 Wait 時(shí),它釋放對(duì)象的鎖并進(jìn)入對(duì)象的等待隊(duì)列,對(duì)象的就緒隊(duì)列中的下一個(gè)線程(如果有)獲取鎖并擁有對(duì)對(duì)象的獨(dú)占使用。Wait()就是交出鎖的使用權(quán),使線程處于阻塞狀態(tài),直到再次獲得鎖的使用權(quán)。

2.Monitor.Pulse方法
當(dāng)前線程調(diào)用此方法以便向隊(duì)列中的下一個(gè)線程發(fā)出鎖的信號(hào)。接收到脈沖后,等待線程就被移動(dòng)到就緒隊(duì)列中。在調(diào)用 Pulse 的線程釋放鎖后,就緒隊(duì)列中的下一個(gè)線程(不一定是接收到脈沖的線程)將獲得該鎖。pulse()并不會(huì)使當(dāng)前線程釋放鎖。

?

簡(jiǎn)述:

共用同一lock對(duì)象兩線程不能只調(diào)用Wait(),Wait這個(gè)方法反而放棄了鎖的使用權(quán),同時(shí)阻塞當(dāng)前線程,線程就直接休眠(進(jìn)入WaitSleepJoin狀態(tài)),同時(shí)在主線程中Join這個(gè)work線程時(shí),也就一直不能返回了。線程將一直阻塞。

讓我們首先看看MSDN對(duì)Monitor.Wait的解釋(鏈接見(jiàn)注釋):
釋放對(duì)象上的鎖并阻止當(dāng)前線程,直到它重新獲取該鎖。...

該解釋的確很粗糙,很難理解。讓我們來(lái)看看它下面的備注:
同步的對(duì)象包含若干引用,其中包括對(duì)當(dāng)前擁有鎖的線程的引用、對(duì)就緒隊(duì)列的引用和對(duì)等待隊(duì)列的引用。

這個(gè)多少還給了點(diǎn)東西,現(xiàn)在我們腦海中想像這么一幅圖畫(huà):

Assembly code
|- 擁有鎖的線程 lockObj->|- 就緒隊(duì)列(ready queue) |- 等待隊(duì)列(waitqueue)

當(dāng)一個(gè)線程嘗試著lock一個(gè)同步對(duì)象的時(shí)候,該線程就在就緒隊(duì)列中排隊(duì)。一旦沒(méi)人擁有該同步對(duì)象,就緒隊(duì)列中的線程就可以占有該同步對(duì)象。這也是我們平時(shí)最經(jīng)常用的lock方法。
為了其他的同步目的,占有同步對(duì)象的線程也可以暫時(shí)放棄同步對(duì)象,并把自己流放到等待隊(duì)列中去。這就是Monitor.Wait。由于該線程放棄了同步對(duì)象,其他在就緒隊(duì)列的排隊(duì)者就可以進(jìn)而擁有同步對(duì)象。
比起就緒隊(duì)列來(lái)說(shuō),在等待隊(duì)列中排隊(duì)的線程更像是二等公民:他們不能自動(dòng)得到同步對(duì)象,甚至不能自動(dòng)升艙到就緒隊(duì)列。而Monitor.Pulse的作用就是開(kāi)一次門,使得一個(gè)正在等待隊(duì)列中的線程升艙到就緒隊(duì)列;相應(yīng)的Monitor.PulseAll則打開(kāi)門放所有等待隊(duì)列中的線程到就緒隊(duì)列。

比如下面的程序:

class Program{staticvoid Main(string[] args){new Thread(A).Start();new Thread(B).Start();new Thread(C).Start();Console.ReadLine();}staticobject lockObj = newobject();staticvoid A(){lock (lockObj) //進(jìn)入就緒隊(duì)列 {Thread.Sleep(1000);Monitor.Pulse(lockObj);Monitor.Wait(lockObj); //自我流放到等待隊(duì)列 }Console.WriteLine("A exit...");}staticvoid B(){Thread.Sleep(500);lock (lockObj) //進(jìn)入就緒隊(duì)列 {Monitor.Pulse(lockObj);}Console.WriteLine("B exit...");}staticvoid C(){Thread.Sleep(800);lock (lockObj) //進(jìn)入就緒隊(duì)列 { } Console.WriteLine("C exit...");}}

?

從時(shí)間線上來(lái)分析:

Assembly code T 線程A ---0lock( lockObj ) ---1 { //... 線程B 線程C ---2//... lock( lockObj ) lock( lockObj ) ---3//... { { ---4//... //... ---5//... //... ---6Monitor.Pulse //... ---7Monitor.Wait //... ---8//... Monitor.Pulse ---9//... } } ---10 } 時(shí)間點(diǎn)0,假設(shè)線程A先得到了同步對(duì)象,它就登記到同步對(duì)象lockObj的“擁有者引用”中。時(shí)間點(diǎn)3,線程B和C要求擁有同步對(duì)象,他們將在“就緒隊(duì)列”排隊(duì): |--(擁有鎖的線程) A | 3 lockObj--|--(就緒隊(duì)列) B,C | |--(等待隊(duì)列) 時(shí)間點(diǎn)7,線程A用Pulse發(fā)出信號(hào),允許第一個(gè)正在"等待隊(duì)列"中的線程進(jìn)入到”就緒隊(duì)列“。但由于就緒隊(duì)列是空的,什么事也沒(méi)有發(fā)生。時(shí)間點(diǎn)8,線程A用Wait放棄同步對(duì)象,并把自己放入"等待隊(duì)列"。B,C已經(jīng)在就緒隊(duì)列中,因此其中的一個(gè)得以獲得同步對(duì)象(假定是B)。B成了同步 對(duì)象的擁有者。C現(xiàn)在還是候補(bǔ)委員,可以自動(dòng)獲得空缺。而A則被關(guān)在門外,不能自動(dòng)獲得空缺。 |--(擁有鎖的線程) B | 8 lockObj--|--(就緒隊(duì)列) C | |--(等待隊(duì)列) A 時(shí)間點(diǎn)9,線程B用Pulse發(fā)出信號(hào)開(kāi)門,第一個(gè)被關(guān)在門外的A被允許放入到就緒隊(duì)列,現(xiàn)在C和A都成了候補(bǔ)委員,一旦同步對(duì)象空閑,都有機(jī)會(huì)得它。 |--(擁有鎖的線程) B | 9 lockObj--|--(就緒隊(duì)列) C,A | |--(等待隊(duì)列) 時(shí)間點(diǎn)10,線程B退出Lock區(qū)塊,同步對(duì)象閑置,就緒隊(duì)列隊(duì)列中的C或A就可以轉(zhuǎn)正為擁有者(假設(shè)C得到了同步對(duì)象)。 |--(擁有鎖的線程) C | 10 lockObj--|--(就緒隊(duì)列) A | |--(等待隊(duì)列) 隨后C也退出Lock區(qū)塊,同步對(duì)象閑置,A就重新得到了同步對(duì)象,并從Monitor.Wait中返回... 最終的執(zhí)行結(jié)果就是: B exit... C exit... A exit...

?

由于Monitor.Wait的暫時(shí)放棄和Monitor.Pulse的開(kāi)門機(jī)制,我們可以用Monitor來(lái)實(shí)現(xiàn)更豐富的同步機(jī)制,比如一個(gè)事件機(jī)(ManualResetEvent):

C# code class MyManualEvent
{
  privateobject lockObj =newobject();
  privatebool hasSet =false;
  publicvoid Set()
  {
    lock (lockObj)
    {
      hasSet =true;
      Monitor.PulseAll(lockObj);
    }
   }
  publicvoid WaitOne()
  {
    lock (lockObj)
    {
      while (!hasSet)
      {
        Monitor.Wait(lockObj);
      }
    }
  }
}

class Program
{
  static MyManualEvent myManualEvent =new MyManualEvent();
  staticvoid Main(string[] args)
  {
    ThreadPool.QueueUserWorkItem(WorkerThread, "A");
    ThreadPool.QueueUserWorkItem(WorkerThread, "B");
    Console.WriteLine("Press enter to signal the green light");
    Console.ReadLine();
    myManualEvent.Set(); ThreadPool.QueueUserWorkItem(WorkerThread, "C");
    Console.ReadLine();
  }
  staticvoid WorkerThread(object state)
  {
    myManualEvent.WaitOne();
    Console.WriteLine("Thread {0} got the green light...", state);
  }
}

我們看到了該玩具M(jìn)yManualEvent實(shí)現(xiàn)了類庫(kù)中的ManulaResetEvent的功能,但卻更加的輕便 - 類庫(kù)的ManulaResetEvent使用了操作系統(tǒng)內(nèi)核事件機(jī)制,負(fù)擔(dān)比較大(不算競(jìng)態(tài)時(shí)間,ManulaResetEvent是微秒級(jí),而lock是幾十納秒級(jí))。

例子的WaitOne中先在lock的保護(hù)下判斷是否信號(hào)綠燈,如果不是則進(jìn)入等待。因此可以有多個(gè)線程(比如例子中的AB)在等待隊(duì)列中排隊(duì)。
當(dāng)調(diào)用Set的時(shí)候,在lock的保護(hù)下信號(hào)轉(zhuǎn)綠,并使用PulseAll開(kāi)門放狗,將所有排在等待隊(duì)列中的線程放入就緒隊(duì)列,A或B(比如A)于是可以重新獲得同步對(duì)象,從Monitor.Wait退出,并隨即退出lock區(qū)塊,WaitOne返回。隨后B或A(比如B)重復(fù)相同故事,并從WaitOne返回。
線程C在myManualEvent.Set()后才執(zhí)行,它在WaitOne中確信信號(hào)燈早已轉(zhuǎn)綠,于是可以立刻返回并得以執(zhí)行隨后的命令。

該玩具M(jìn)yManualEvent可以用在需要等待初始化的場(chǎng)合,比如多個(gè)工作線程都必須等到初始化完成后,接到OK信號(hào)后才能開(kāi)工。該玩具M(jìn)yManualEvent比起ManulaResetEvent有很多局限,比如不能跨進(jìn)程使用,但它演示了通過(guò)基本的Monitor命令組合,達(dá)到事件機(jī)的作用。

現(xiàn)在是回答朋友們的疑問(wèn)的時(shí)候了:
Q:?Lock關(guān)鍵字不是有獲取鎖、釋放鎖的功能... 為什么還需要執(zhí)行Pulse?
A: 因?yàn)閃ait和Pulse另有用途。

Q:?用lock 就不要用monitor了(?)
A: lock只是Monitor.Enter和Monitor.Exit,用Monitor的方法,不僅能用Wait,還可以用帶超時(shí)的Monitor.Enter重載。

Q:?Monitor.Wait完全沒(méi)必要 (?)
A: Wait和Pulse另有用途。

Q:?什么Pulse和Wait方法必須從同步的代碼塊內(nèi)調(diào)用?
A: 因?yàn)閃ait的本意就是“[暫時(shí)]釋放對(duì)象上的鎖并阻止當(dāng)前線程,直到它重新獲取該鎖”,沒(méi)有獲得就談不到釋放。


我們知道lock實(shí)際上一個(gè)語(yǔ)法糖糖,C#編譯器實(shí)際上把他展開(kāi)為Monitor.Enter和Monitor.Exit,即:

C# code
lock(lockObj) {?//...}?////相當(dāng)于(.Net4以前):Monitor.Enter(lockObj);?try{?//...}?finally{ Monitor.Exit(lockObj); }


但是,這種實(shí)現(xiàn)邏輯至少理論上有一個(gè)錯(cuò)誤:當(dāng)Monitor.Enter(lockObj);剛剛完成,還沒(méi)有進(jìn)入try區(qū)的時(shí)候,有可能從其他線程發(fā)出了Thread.Abort等命令,使得該線程沒(méi)有機(jī)會(huì)進(jìn)入try...finally。也就是說(shuō)lockObj沒(méi)有辦法得到釋放,有可能造成程序死鎖。這也是Thread.Abort一般被認(rèn)為是邪惡的原因之一。

DotNet4開(kāi)始,增加了Monitor.Enter(object,ref bool)重載。而C#編譯器會(huì)把lock展開(kāi)為更安全的Monitor.Enter(object,ref bool)和Monitor.Exit:

C# code
lock(lockObj) {?//...}?////相當(dāng)于(DotNet 4):boollockTaken?=false;?try{ Monitor.Enter(lockObj,reflockTaken);?//?}?finally{?if(lockTaken) Monitor.Exit(lockObj); }


現(xiàn)在Monitor.TryEnter在try的保護(hù)下,“加鎖”成功意味著“放鎖”將得到finally的保護(hù)。

轉(zhuǎn)載于:https://www.cnblogs.com/StupidsCat/archive/2013/01/05/2845505.html

總結(jié)

以上是生活随笔為你收集整理的C# 多线程控制 通讯 和切换的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

激情婷婷色| 91精品久久久久久久久久入口 | 免费日韩三级 | 精品国产成人av在线免 | 国产午夜精品久久 | 丁香电影小说免费视频观看 | 亚洲精品视频在线观看视频 | 午夜三级福利 | 五月天色综合 | 菠萝菠萝蜜在线播放 | 国产精品国内免费一区二区三区 | 日韩视频精品在线 | 亚洲综合成人av | 99精品在线观看视频 | 国产一区二区精品久久 | av中文字幕在线看 | 久久婷婷色 | 天天人人综合 | av免费网页| 日日干日日操 | 欧美 日韩 视频 | 婷婷网站天天婷婷网站 | 色狠狠一区二区 | 天天狠狠| 天天干视频在线 | 国产不卡av在线播放 | www.色爱| 国产在线视频不卡 | 99精品国产一区二区三区麻豆 | 亚洲精品乱码久久 | 92精品国产成人观看免费 | 99久久精品午夜一区二区小说 | 国产成人在线免费观看 | 亚洲区视频在线 | 色婷婷综合久色 | 毛片网站免费在线观看 | 日韩av在线免费看 | 午夜视频在线观看一区二区三区 | 亚洲国内在线 | 手机在线黄色网址 | 久久理论片 | av在线免费不卡 | 一区二区三区高清在线观看 | 久久免费视频在线观看6 | 黄色的网站在线 | 亚洲国产成人精品电影在线观看 | 婷婷播播网 | 在线视频 91| 亚州av一区 | 欧美日韩在线播放一区 | 91自拍视频在线观看 | 91天堂在线观看 | 亚洲视频观看 | 91免费版在线观看 | 狠狠色丁香婷婷综合基地 | 免费成人av | 日韩在线观看视频中文字幕 | 超碰最新网址 | www在线观看视频 | av女优中文字幕在线观看 | 国内精品免费 | 亚洲成人国产 | 欧美日韩在线观看一区 | 亚洲情感电影大片 | 欧美一级淫片videoshd | 亚洲精品久久久久久久不卡四虎 | 久久久久久久av麻豆果冻 | 精品久久久久免费极品大片 | 久久视频国产 | 91中文字幕一区 | 欧洲精品久久久久毛片完整版 | 久久免费黄色大片 | 91精品国产综合久久久久久久 | 伊人色综合久久天天网 | 久久超碰免费 | 美女av免费看 | 天天操天天干天天操天天干 | 黄色特级片 | 国内精品久久久久久久久 | 久久极品 | 久久久久久久久久久福利 | av福利免费 | 激情五月婷婷丁香 | 97超碰中文字幕 | 国产第一福利 | 黄a网| 婷婷丁香综合 | 亚洲精品久久视频 | www.天天色 | 在线观看一区二区视频 | 在线看毛片网站 | 亚洲成人黄色在线观看 | 青青河边草手机免费 | 婷婷色综合网 | 日本精品小视频 | 日韩久久久久久久久久 | 久久久国产精品网站 | 91看片在线播放 | 久久久久久美女 | 亚洲精品在线观看av | 97色se| 九九久久久久久久久激情 | 国产中文字幕第一页 | 午夜91在线 | 色婷婷av国产精品 | 精品国产视频一区 | 五月天高清欧美mv | 天天干夜夜夜操天 | 成人在线观看资源 | 久亚洲精品 | 成人全视频免费观看在线看 | 黄免费网站| 在线视频a | 香蕉视频久久久 | 欧美特一级 | 亚洲精品动漫久久久久 | 国产亚洲激情视频在线 | 在线97 | 亚州激情视频 | 色av色av色av | 亚洲一区欧美激情 | 高清不卡一区二区三区 | 免费看在线看www777 | 国产精品第2页 | 国产一区在线精品 | 亚洲综合欧美精品电影 | 免费视频a | 国内成人精品2018免费看 | 国产小视频在线免费观看视频 | 午夜在线日韩 | 国产福利免费在线观看 | 国产不卡免费视频 | 日韩视频一 | av中文字幕亚洲 | www.xxx.性狂虐 | 中文字幕在线视频网站 | 国内精品视频一区二区三区八戒 | 国产原创在线 | 欧美成天堂网地址 | 五月天久久精品 | 日韩av电影中文字幕 | 日韩大片免费在线观看 | 91久久电影 | 天堂av网在线| 日韩影视在线观看 | 成 人 免费 黄 色 视频 | 色婷婷啪啪免费在线电影观看 | 久久久久夜色 | 在线播放第一页 | 青青看片 | 亚洲精品午夜aaa久久久 | 丁香激情综合 | 国产精品黄色在线观看 | 狠狠干夜夜爽 | 免费高清在线观看成人 | 综合在线色| 成人在线观看资源 | 国产精品丝袜久久久久久久不卡 | 香蕉久草在线 | 天天射天天射天天射 | 在线精品视频免费观看 | 国产高清视频网 | 中文字幕在线观看2018 | 91久久奴性调教 | 午夜影院一级 | 日日夜夜狠狠干 | 激情一区二区三区欧美 | 免费亚洲黄色 | 四虎视频 | 久久这里只有精品视频99 | 在线观看免费av网站 | bbbb操bbbb | 国产中的精品av小宝探花 | 色婷婷国产精品一区在线观看 | 麻豆传媒视频观看 | 欧美日本国产在线观看 | 日日夜夜爱 | 日日射av| 久久国产精品影视 | 免费视频久久久久久久 | 天天天综合 | 国产亲近乱来精品 | 国产精品网红直播 | 在线观看免费视频你懂的 | 怡红院av久久久久久久 | 久久精品成人欧美大片古装 | 99麻豆久久久国产精品免费 | 在线99热 | 最近中文字幕免费视频 | 免费在线观看成人av | 99色在线观看视频 | 精品在线亚洲视频 | 久久久久久国产精品免费 | 欧美精品在线观看免费 | 黄色成人影视 | 久久免费在线观看 | 免费视频一二三区 | www.com在线观看 | 夜夜操网| 亚洲婷婷网 | 亚洲精品综合欧美二区变态 | 永久免费精品视频 | 久久草在线视频国产 | 人人擦| 一性一交视频 | 国产在线观看免费 | 精品国产123 | 久久久久久免费毛片精品 | 天天操天天干天天操天天干 | 亚洲欧美综合精品久久成人 | 亚洲天堂在线观看完整版 | 欧美一级看片 | 91久久一区二区 | 最近日本字幕mv免费观看在线 | 天天干,夜夜操 | 日日爱999| 日日躁天天躁 | 国产99久久久精品 | 久久呀| 欧美怡红院| 精品久久久久久综合日本 | 亚洲国产精品va在线 | 欧美一级片在线观看视频 | 97人人爽 | 2024国产在线 | 在线视频观看亚洲 | 91精品久久久久久综合五月天 | 欧美高清成人 | 久草视频手机在线 | 国产免费观看久久黄 | 国产一级二级三级在线观看 | 911精品美国片911久久久 | 99精品免费在线观看 | 亚洲精品tv久久久久久久久久 | 激情视频一区二区三区 | 亚洲一级二级三级 | 久久免费精品 | v片在线看 | 久久免费在线视频 | 亚洲精品av中文字幕在线在线 | 国产短视频在线播放 | 夜夜爽88888免费视频4848 | 天天碰天天操视频 | 中文国产字幕在线观看 | 久久综合欧美精品亚洲一区 | 日本中文字幕网 | 69久久夜色精品国产69 | 精品亚洲男同gayvideo网站 | 亚洲视频1区2区 | 五月天色综合 | 日日夜日日干 | 亚洲a在线观看 | 亚洲精品玖玖玖av在线看 | 麻豆影视在线免费观看 | 国内精品久久久久影院日本资源 | 日韩黄色免费 | 亚洲日本va在线观看 | 日韩免费久久 | 五月天色综合 | 亚洲香蕉在线观看 | 欧美日韩高清一区二区 | av免费电影在线 | 久久草精品 | 成人免费xyz网站 | 在线精品视频免费播放 | 激情网婷婷 | 成人国产电影在线观看 | 国产精品久久9 | 亚洲无吗av | 成人黄色在线看 | 国产日产在线观看 | 免费午夜视频在线观看 | 国产精品尤物视频 | 欧美一二区在线 | 俺要去色综合狠狠 | 欧美不卡视频在线 | 91欧美精品| 久久99国产精品久久 | 黄色国产高清 | 五月天视频网 | 808电影免费观看三年 | 日本女人逼 | 欧美黄色成人 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 亚洲激情 在线 | 久久久网页 | 国产视频观看 | 在线观看日韩精品 | 伊人狠狠色 | 国产亚洲精品久久久久久网站 | 国产精品少妇 | 亚洲精品免费在线视频 | 久久久99国产精品免费 | 免费看色视频 | 国产免费久久久久 | 在线电影av | 国产在线观看你懂的 | 91九色国产蝌蚪 | 久草在线视频看看 | 成人在线免费看 | 在线观看视频你懂得 | 成人午夜久久 | 亚洲精品国产高清 | 国产美女免费看 | www.香蕉| 国产麻豆剧果冻传媒视频播放量 | 亚洲一级性 | 91爱爱视频 | 欧美一区二区在线免费看 | 18岁免费看片 | 日韩激情视频在线 | 国产黄色片一级三级 | 欧美做受69 | 久久精品国产v日韩v亚洲 | 国产高清视频免费 | 啪啪午夜免费 | 人人干人人添 | 精品人妖videos欧美人妖 | 精品91久久久久 | 综合网成人| 黄色av电影免费观看 | 又黄又爽的视频在线观看网站 | 国产黄影院色大全免费 | 久久天天躁狠狠躁亚洲综合公司 | 国产成人av一区二区三区在线观看 | 欧美另类色图 | 91精品毛片 | 精久久久久 | 国产精品毛片久久久 | 久久免费激情视频 | 西西444www高清大胆 | 欧美激情综合色综合啪啪五月 | 亚洲国产精品久久久久久 | 亚洲国产网址 | 久草电影网 | 亚洲国产大片 | 激情综合亚洲 | 九九久久婷婷 | av综合网址 | www.在线看片.com | 三上悠亚一区二区在线观看 | 偷拍精偷拍精品欧洲亚洲网站 | 日韩免 | 91麻豆文化传媒在线观看 | 91久久精品一区二区二区 | 成人免费一区二区三区在线观看 | 国产成人黄色在线 | 色综合天天综合网国产成人网 | 黄色av影院 | 久草在线资源观看 | 国产精品视频999 | 久久久影片 | 911久久香蕉国产线看观看 | 日韩理论 | 伊甸园永久入口www 99热 精品在线 | 久久精品免费看 | 国产一级大片免费看 | 国产黄色片免费观看 | 国产精品久久久久久一区二区 | 欧美日bb| 在线观看av免费观看 | 亚洲欧美精品一区二区 | 国产精品久久久久久久久软件 | 91九色蝌蚪国产 | 国产中文字幕视频在线观看 | 亚洲天天综合网 | 亚洲高清色综合 | 色橹橹欧美在线观看视频高清 | 久久久久国产精品视频 | 色婷婷骚婷婷 | 精品国产一区二区三区av性色 | 日日夜夜精品免费 | 亚洲精品在线免费 | 午夜精品婷婷 | 免费在线观看黄色网 | 国产亚洲精品久久久久久网站 | 夜夜躁日日躁狠狠躁 | 午夜视频在线瓜伦 | 欧美一区二区三区免费看 | 婷婷综合国产 | 青青草视频精品 | 伊人www22综合色 | 美女av免费看| 66av99精品福利视频在线 | 久久电影日韩 | 一区 二区 精品 | 美女免费黄网站 | 亚洲天堂毛片 | 99精品热| 亚洲国产69| 超碰97中文 | 少妇自拍av | 国产 日韩 在线 亚洲 字幕 中文 | 波多野结衣一区二区 | 91黄色小视频 | 日韩中文在线播放 | 久久99精品久久久久婷婷 | 午夜免费电影院 | 国产一区二区在线免费 | 成年人视频在线免费观看 | 国产亚洲精品久 | 九九免费在线观看视频 | 免费高清在线观看成人 | 96av麻豆蜜桃一区二区 | 3d黄动漫免费看 | 免费在线黄色av | 亚洲午夜精品久久久久久久久久久久 | 四虎伊人 | 丝袜美女在线 | 亚洲国产av精品毛片鲁大师 | 9797在线看片亚洲精品 | 91视频在线免费看 | 日韩三级成人 | 天天综合天天做天天综合 | www.久久婷婷 | 免费在线激情电影 | 叶爱av在线 | 日韩黄色网络 | 久久午夜国产精品 | 91成人精品一区在线播放69 | 91香蕉视频在线 | 国产亚洲片 | 狠狠色丁香婷婷综合久小说久 | 国产成人一二片 | 婷婷色吧| 欧美日韩视频一区二区三区 | 久久久婷 | 国产午夜在线观看视频 | av三区在线 | 69亚洲乱| 五月天电影免费在线观看一区 | 国产视频在线观看一区二区 | 我爱av激情网 | 午夜精品久久久久99热app | 成全免费观看视频 | 99热最新地址 | 九九九热| 午夜av剧场| 麻豆免费视频网站 | 在线激情电影 | 天天综合人人 | 玖玖视频国产 | 日韩精品久久久久久 | 波多野结衣视频一区二区三区 | 国产在线视频一区二区 | 亚洲天堂网在线观看视频 | 最新日韩中文字幕 | 三级av免费 | 国产尤物一区二区三区 | av免费在线看网站 | 91av在线电影 | 综合色综合 | 久久国产精品免费一区 | 国产黄色片久久 | 欧美午夜精品久久久久久浪潮 | 久久综合影视 | 福利区在线观看 | 久久久精品欧美一区二区免费 | 天天天综合 | 天天干天天干天天 | 国产在线观看中文字幕 | 午夜久久成人 | 人人添人人澡人人澡人人人爽 | 久久久久国产精品一区 | 国产精品一区电影 | 97色国产 | 婷久久| 91中文视频| 97理论电影 | 探花系列在线 | 国产香蕉97碰碰碰视频在线观看 | 欧美a级在线免费观看 | 亚洲成人在线免费 | 亚洲精欧美一区二区精品 | 色综合久久久久综合体桃花网 | 国产高清在线观看av | 在线观看国产一区二区 | 久久美女高清视频 | 91看片在线看片 | 国内精品亚洲 | 成全免费观看视频 | 夜夜操天天操 | 日韩区欧美久久久无人区 | 成人sm另类专区 | 国产精品免费观看网站 | 欧美日韩亚洲在线观看 | 国产精品一区二区av麻豆 | 高清在线一区二区 | 精品一区二区三区久久久 | 一区二区三区精品在线 | 婷婷av资源| 天天拍天天爽 | 9999在线 | 国产日韩在线播放 | 伊人天堂网 | 婷婷激情久久 | 91精品国产三级a在线观看 | 美女视频免费精品 | www夜夜操 | 国产欧美日韩一区 | 女人魂免费观看 | 超级碰碰免费视频 | 国产婷婷精品av在线 | 91pony九色丨交换 | 国产亚州av | 久久国产电影院 | 久久国产色 | 国产91aaa | 人人看看人人 | 亚洲综合五月 | 亚洲精品视频偷拍 | 99这里只有| 国产成人黄色 | 欧美激情精品久久久久久免费印度 | 中文字幕一区二区三区在线播放 | 在线成人一区 | 精品91在线| 免费三级影片 | 黄污网| 亚洲 欧美 国产 va在线影院 | 亚洲精品国产精品国自产在线 | 美女在线观看网站 | 国产成人精品久久亚洲高清不卡 | 日韩伦理片hd | 97福利视频 | 丁香免费视频 | 欧美午夜精品久久久久久浪潮 | 国产美女精品视频免费观看 | 婷婷综合伊人 | 亚洲欧洲成人 | 97人人模人人爽人人喊网 | 99r精品视频在线观看 | 在线观看日韩免费视频 | 97人人模人人爽人人少妇 | 特级西西444www大精品视频免费看 | 亚洲人片在线观看 | 国产精品午夜久久久久久99热 | 伊人六月 | 美女免费视频观看网站 | 日韩精品2区 | 草久久av| 久久综合视频网 | 欧美精品国产综合久久 | 日本 在线 视频 中文 有码 | 精精国产xxxx视频在线播放 | 国产99免费 | 国产精品video爽爽爽爽 | 久久久久久久久久久久国产精品 | 丝袜一区在线 | 亚洲在线看 | 国产成人久| av中文字幕不卡 | 九色porny真实丨国产18 | 国产精品福利在线观看 | 亚洲我射av | 在线观看成人小视频 | 丁香资源影视免费观看 | 一区二区三区视频网站 | 欧美日韩久久不卡 | 亚洲欧洲成人 | 亚洲成色777777在线观看影院 | 久久国产网站 | 成人一级免费电影 | 最近中文字幕免费观看 | 精品国产免费一区二区三区五区 | 国产精品夜夜夜一区二区三区尤 | 欧洲色综合 | 国产精品成久久久久 | 免费 在线 中文 日本 | 亚洲精品视频一二三 | 韩国精品一区二区三区六区色诱 | 国产成人一区二区三区影院在线 | 久草在线观看资源 | 激情综合亚洲精品 | 天天射日 | 亚洲午夜精品久久久久久久久久久久 | 国产网红在线观看 | 最新av电影网址 | 综合色站| 免费视频你懂得 | 有码中文字幕 | 亚洲精品在线观看不卡 | 国产精品麻 | 97在线免费观看视频 | 色资源网免费观看视频 | 天天操夜夜操夜夜操 | 一区二区在线不卡 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 久草免费在线 | 久久亚洲视频 | 久久久久久久久久久网站 | 久久久久亚洲精品成人网小说 | 国产久草在线观看 | 成人在线视频网 | 久久天天躁狠狠躁亚洲综合公司 | 另类老妇性bbwbbw高清 | 色婷婷电影 | 国内毛片毛片 | 一区二区三区中文字幕在线观看 | 麻豆视频www| 美女激情影院 | 成人三级视频 | 五月天亚洲婷婷 | 99久久精品免费 | 国产免费区 | 亚洲综合爱 | 色播六月天| 超碰在线94 | 久久九九精品久久 | 男女男视频 | 久草视频资源 | 精品亚洲欧美无人区乱码 | 日本精品中文字幕 | 免费黄av| 欧美日韩综合在线观看 | 国产精品免费成人 | 韩日视频在线 | 五月天综合网站 | 久久日韩精品 | 国产精品成人免费一区久久羞羞 | 波多野结衣亚洲一区二区 | 亚洲国产大片 | 国产手机免费视频 | 亚洲精品成人在线 | 国产v在线 | 亚洲欧美乱综合图片区小说区 | 国产精品久久久久999 | 国产免费一区二区三区最新 | 在线亚洲欧美日韩 | 久久综合精品国产一区二区三区 | 国产在线日韩 | 女人18片| 国产黄av | 欧美大片在线观看一区 | 看毛片网站| 一区二区欧美在线观看 | av电影av在线 | av片子在线观看 | 免费成人在线观看 | 99久久精品国 | 欧美一二三区在线播放 | 日韩在线观看一区 | 久久一区二区免费视频 | 国产午夜精品视频 | 国产成人久久精品亚洲 | 丁香激情五月婷婷 | 在线观看久草 | 免费在线a| 中文字幕精品三区 | 久久久久久久久毛片 | 九九久久在线看 | 亚洲精品在线观看网站 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产一级a毛片视频爆浆 | 激情欧美一区二区免费视频 | 国产在线p | 国内久久久久久 | 人人玩人人添人人 | 啪啪午夜免费 | 亚洲一区免费在线 | 欧美另类美少妇69xxxx | av在线收看 | 探花在线观看 | 97香蕉视频 | 国产精品久久久久久久久久妇女 | 婷婷日日 | 2019免费中文字幕 | 国产理伦在线 | 国产性天天综合网 | 国产手机在线精品 | 中文字幕日韩伦理 | 不卡精品 | 欧美日韩国产一区二区三区 | 国产精品国产三级国产aⅴ9色 | 激情欧美一区二区免费视频 | 国产成人高清在线 | 黄色免费电影网站 | 亚洲人成免费网站 | 一本大道久久精品懂色aⅴ 五月婷社区 | 久久久鲁| 亚洲伊人婷婷 | 婷婷激情五月 | 久久人人爽人人爽人人片av免费 | 精品一区久久 | 天天爽天天碰狠狠添 | 国产精品免费成人 | 午夜免费电影院 | 91精品夜夜 | 国内精品久久久久影院优 | 蜜臀av性久久久久av蜜臀妖精 | 久久69精品 | 成人黄色电影在线播放 | 免费欧美| 亚洲精品视频网站在线观看 | 一级电影免费在线观看 | 少妇搡bbbb搡bbb搡忠贞 | 91九色蝌蚪| 亚洲一区精品二人人爽久久 | 久久av电影 | 黄色看片 | 成人黄色小说网 | 久久伦理视频 | 国产精品观看视频 | 日韩成片 | 中文字幕视频三区 | 一区二区三区四区五区在线 | 国产精品久久久久影视 | 81国产精品久久久久久久久久 | 国产精品久久久久久久久久久杏吧 | 91香蕉视频在线下载 | av一级在线观看 | 91九色国产在线 | 国产精品欧美激情在线观看 | 六月色| 五月香视频在线观看 | 国产成人精品亚洲精品 | 国产中文字幕在线免费观看 | 亚洲1区 在线 | 人人爽爽人人 | 四虎免费在线观看视频 | 香蕉久久久久 | 97精品超碰一区二区三区 | 欧美激情精品久久久久久免费 | 在线看v片成人 | 黄色资源在线 | 黄色的视频网站 | 中文字幕二区在线观看 | 亚洲特级片 | 干干日日| 欧美成人黄色 | 成人理论在线观看 | 天天舔天天搞 | 国产精品一区二区三区免费视频 | 日批视频| 久久久久久久久久免费 | 国产麻豆视频网站 | 人人澡人人草 | 久久视频精品在线观看 | 亚洲视频在线免费看 | 97国产视频 | 欧美怡红院 | 97视频资源 | 99在线观看视频网站 | 狠狠狠狠狠狠干 | 久草在线久草在线2 | 亚洲精品国产成人av在线 | 四虎伊人| 91av在线视频播放 | 欧美日视频 | 日日夜夜天天射 | 亚洲天天 | 婷婷六月天天 | 久久久精品久久 | 久久涩涩网站 | 欧美资源 | 亚洲精品中文字幕视频 | 国产一级片播放 | 狠狠色狠狠色综合日日92 | 成人国产精品 | 国产精品欧美久久久久无广告 | 午夜精品久久久99热福利 | 国产精品18久久久久久不卡孕妇 | 国产精品1区2区3区在线观看 | 精品国产乱码一区二 | 色狠狠久久av五月综合 | 国产96av| 久久这里精品视频 | 久久久久国产一区二区三区四区 | 狠狠亚洲| 日本不卡123区 | 91成人免费视频 | 国产精品久久久久久久久久久免费看 | 91xav| 久亚洲 | 久久久精品久久日韩一区综合 | 国产成人99av超碰超爽 | 成人黄色电影在线 | 一区二区三区久久 | www..com毛片 | 国产高清在线不卡 | 粉嫩av一区二区三区入口 | 国产黄色精品在线观看 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 日韩高清www| 久日视频| 涩涩在线 | 久久国产高清视频 | 91中文字幕一区 | 伊人久久影视 | 天天草天天插 | 99在线精品视频在线观看 | 色999精品| 成人av在线直播 | 色婷婷99 | 久久中文字幕导航 | 91人人插 | 狠狠色伊人亚洲综合成人 | 在线性视频日韩欧美 | 91成人免费| 99久久激情视频 | 91丨九色丨国产在线 | 亚洲精品国久久99热 | 在线免费看黄网站 | 国产精品女视频 | 免费成人av网站 | 激情一区二区三区欧美 | 久久综合中文色婷婷 | 成人免费xxxxxx视频 | 天堂资源在线观看视频 | 18久久久 | 97免费在线观看视频 | 国产亚洲在线观看 | 国产一区二区三区免费在线观看 | 91 中文字幕 | 99色在线 | 国产精品成人免费精品自在线观看 | 亚洲五月婷婷 | 精品久久久久免费极品大片 | 国产视频久久久久 | 日韩精品一区二区在线视频 | 中文字幕在线播放视频 | 97国产视频 | 中文字幕亚洲情99在线 | 亚洲成熟女人毛片在线 | 天天射天天操天天色 | 免费网站色 | 成人久久18免费网站麻豆 | 国产精品资源在线观看 | 精品国产_亚洲人成在线 | 婷婷久草 | 国产成人免费观看 | av免费网站在线观看 | 久草电影免费在线观看 | 亚洲成人在线免费 | 亚洲黄色高清 | 蜜桃麻豆www久久囤产精品 | 日韩二区三区在线 | 中字幕视频在线永久在线观看免费 | 美女很黄免费网站 | 色综合激情网 | 日韩综合一区二区 | 精品国产亚洲在线 | 国产小视频在线看 | 狠狠狠狠狠狠狠狠 | 在线视频第一页 | 麻豆免费视频网站 | 三级黄色大片在线观看 | 中文字幕精品一区二区三区电影 | 成人黄色毛片视频 | 国产资源网 | 亚洲精品成人 | 国产三级精品三级在线观看 | 午夜狠狠干 | 亚洲一二区视频 | 亚洲 欧美 91 | 中文字幕在线播放第一页 | 国内精品视频一区二区三区八戒 | 亚洲精品国偷拍自产在线观看蜜桃 | 三上悠亚一区二区在线观看 | 精品一区久久 | 亚洲欧美va | 又大又硬又黄又爽视频在线观看 | 99久久精品国产一区二区三区 | 亚洲精品在线免费看 | 国产精品剧情在线亚洲 | 天天做天天干 | 一区二区三区精品在线视频 | 日本韩国精品在线 | 干干夜夜| 国产一区在线视频播放 | 日韩美视频 | 日韩在线观看 | 国产日韩av在线 | 中文字幕网站视频在线 | 91精品视频在线看 | 亚洲视频 在线观看 | 国产精品二区三区 | 欧美日韩视频 | 成年人黄色av | 久久99久久99精品免费看小说 | 丁香激情网 | 91看片一区二区三区 | 久久综合久色欧美综合狠狠 | 日韩欧在线 | 日韩视频中文字幕在线观看 | 中文字幕三区 | 国内外成人在线视频 | 97免费视频在线播放 | 国产无区一区二区三麻豆 | 激情av在线播放 | 91视频在线免费 | 国产色综合 | av中文电影 | 国产精品日韩欧美一区二区 | 人人爽人人爽人人片 | 天天玩天天干 | 日三级在线 | 久久久久国产一区二区三区 | 美女视频免费一区二区 | 特级aaa毛片 | 三级黄在线 | 免费视频一二三区 | 国产 一区二区三区 在线 | 国产精品黄色 | 丰满少妇久久久 | 亚洲永久免费av | 午夜电影中文字幕 | 久久久久久久久久久久久久免费看 | 在线国产91 | av永久网址 | 欧美巨大荫蒂茸毛毛人妖 | 91色偷偷 | 91精品成人 | 久操久 | 超碰在线官网 | 亚洲自拍偷拍色图 | 欧美综合干 | 欧美99久久 | 99re中文字幕 | 美女福利视频网 | 成人在线免费视频 | 国产1区2区3区精品美女 | 97高清免费视频 | www日韩精品 | 在线免费观看羞羞视频 | av电影 一区二区 | 五月婷在线 | 福利视频午夜 | 天堂网一区 | 日韩欧美不卡 | 美女视频免费精品 | 午夜18视频在线观看 | 国产在线超碰 | 又色又爽又黄高潮的免费视频 | 亚洲欧美999| 国产福利一区二区在线 | 精品在线观看一区二区 | 亚洲激情婷婷 | 深爱婷婷激情 | 视频在线观看国产 | 国产高清网站 | 99日精品| 粉嫩av一区二区三区免费 | 天天综合精品 | 国产日韩一区在线 | 国产精品久久久久一区二区三区共 | 午夜影院一级 | 亚洲精品乱码久久久久久 | 国产精品视频久久久 | 不卡视频在线看 | 超碰在线最新网址 | 中文字幕在线观看播放 | 国产私拍在线 | 美女黄色网在线播放 | 亚洲综合在线视频 | 国产精品一区二区三区在线看 | 一区二区三区四区在线免费观看 | 国产视频网站在线观看 | 美女福利视频一区二区 | jizzjizzjizz亚洲 | 丁香花在线视频观看免费 | 五月婷婷开心中文字幕 | 国产色婷婷精品综合在线手机播放 | 国产亚洲日 | 久草免费福利在线观看 | 超碰在线97观看 | 四虎成人精品永久免费av | 在线观看av麻豆 | 欧美孕妇与黑人孕交 | 国产字幕在线看 | 日韩精品一区二区三区免费观看 | 久久综合免费视频影院 | 日韩大片在线 | 欧美91成人网 | 久久久久久国产精品亚洲78 | 国产亚洲人成网站在线观看 | 免费观看的黄色片 | 欧美先锋影音 | 麻豆一区二区 | 丁香高清视频在线看看 | 丁香综合网 | 一本一本久久a久久精品综合小说 | 丁香六月色 | 久久国产一区 | 免费三级黄 | 色狠狠狠 | 亚洲精品视频中文字幕 | 久久99亚洲精品 | 国产特级毛片 | 天干啦夜天干天干在线线 | 国产精品福利视频 | 免费亚洲视频在线观看 | 狠狠干成人 | 久久综合偷偷噜噜噜色 | 婷婷五情天综123 | 天天天天爽 | 91大神一区二区三区 | 国产在线黄 |