C# 多線程 信號量 同步互斥


問題詳情,參見鏈接。

程序(program) :計算機能識別和執行的指令集合

進程(process):在一個操作系統運行中,有許多個進程在工作,每一個進程都是某個存在於硬盤中的可執行程序執行狀態的一個實例,是操作系統分配計算機資源的最小單元.每一個進程都有自己的地址空間、內存(線程間不可直接共享各自內存)、數據棧以及其它記錄器運行軌跡的輔助數據。進程代表CPU所能處理的單個任務。任一時刻,CPU總是運行一個進程,其他進程處於非運行狀態。 

線程(Thread):一個標准的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程的一個實體,線程是獨立調度的基本單位,共享進程資源 。一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以並發執行。由於線程之間的相互制約,致使線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。每一個程序都至少有一個線程,那就是線程本身。線程使用某些共享內存時,其他線程必須等它結束,才能使用這一塊內存。

減少了程序並發時所付出的時空開銷,並且可以高效的共享數據,

1.進程時動態的,代表程序的一次執行任務,而程序是靜態的,程序是指令的集合

進程和線程的區別:
  1.進程是操作系統分配資源的基本單位(搶占CPU資源),擁有完整的內存空間;一個進程的內存空間是共享的,每個線程都可以使用這些共享內存。
  2.一個進程有一個至多個線程
  3.一個進程異常退出不會引起另外的進程運行異常;但是線程若異常退出一般是會引起整個進程奔潰。
  4.創建/撤銷/切換 進程的開銷遠大於線程的(創建線程比創建進程快)

 

進程可以調用一個或多個程序的,,比如動態鏈接調用

線程是並發的——每個線程都處於執行過程中的某個狀態。

Semaphore(信號量)是用來控制同時訪問特定資源的線程數量,它通過協調各個線程,以保證合理的使用公共資源。最大並發數   並發訪問線程最大個數  

 

信號量給資格(處於可執行狀態)  CPU給權力

Mutex 在給線程/進程間加鎖時

並行與並發
並發:交替   線程  同一時間片段同時執行  代碼的性質,實際還是按順序執行
並行:同時   進程  同一時間點同時執行    物理運行狀態

同步:  多個線程並行,安排執行順序   在互斥基礎上,控制資源的訪問順序   )

互斥:一個線程修改變量,別的線程不能訪問   加鎖/互斥信號量  不可以同時訪問臨界資源

信號量:實現線程同步

  信號量的值為非負整數,其值為0時,表示當前系統中無此類資源

  信號量代表資源,其值表示資源的數

   P(申請資源)  V(釋放資源

  P(S):  

    if(信號量值>0)  {申請資源的線程繼續執行,信號量值-1} else  {申請資源的線程阻塞}

  V(S) 

    if(沒有線程在等待該資源){信號量值-1} else{ 喚醒第一個等待的線程,讓其繼續運行;}

同步請求:發起請求,然后等待,當執行完請的回調函數才繼續執行請求代碼塊之后的代碼,如果一直沒又響應,會阻塞請求代碼塊后面代碼執行
異步請求:發起請求,繼續執行請求代碼塊之后的代碼,不會阻塞請求代碼塊后面代碼的執行,當請求被響應時,系統會通知進程處理。這樣提高執行效率。

黑白子

兩白一黑
using System.Threading;//+ 線程
namespace 黑白子
{
    class Program
    {
        private static Semaphore white = new Semaphore(1, 1);//信號量,第一位數是1,所以先執行white.WaitOne()。
        private static Semaphore black = new Semaphore(0, 1);//信號量
        private static int count = 0;
        static void Main(string[] args)
        {
            Thread bla = new Thread(Black);
            Thread whi = new Thread(White);
            bla.Start();
            whi.Start();
        }

        private static void Black() 
        {
            for (; ; ) 
            {
                black.WaitOne();
                Console.WriteLine("撿黑子");
                Thread.Sleep(1000);
                white.Release();
            }
        }

        private static void White()
        {
            for (; ; )
            {
                white.WaitOne();
                Console.WriteLine("撿白子");
                Thread.Sleep(1000);
                count++;
                if (count % 2 == 0)
                    black.Release();
                else
                    white.Release();
                
            }
        }
    }
}
一黑一白
using System.Threading;
namespace blackwhite
{
    class Program
    {
        private static Semaphore white;
        private static Semaphore black;
        static void Main(string[] args)
        {
            white = new Semaphore(0, 1);
            black = new Semaphore(0, 1);
            Thread pwhite = new Thread(Pwhite);
            Thread pblack= new Thread(Pblack);

            white.Release();
            pwhite.Start();
            pblack.Start();
        }
        protected static void Pwhite()
        {
            while (true)
            {  
            white.WaitOne();
            Console.WriteLine("撿白子");
            black.Release();
            Thread.Sleep(300);
            }   
        }
        protected static void Pblack()
        {
            while (true)
            {
                black.WaitOne();
                Console.WriteLine("撿黑子");
                white.Release();
                Thread.Sleep(300);
                Console.WriteLine();
            }  
        }
    }
}

蘋果桔子

using System.Threading;
public class Class1
{
    private static Semaphore empty, apple, orange;
    static void Main(String[] args)
    {
        empty = new Semaphore(1, 1);
        apple = new Semaphore(0, 1);
        orange = new Semaphore(0, 1);
        Thread father = new Thread(Father);
        Thread mother = new Thread(Mother);
        Thread daughter = new Thread(Daughter);
        Thread son = new Thread(Son);
        father.Start(); daughter.Start();
        mother.Start(); son.Start();
    }
    protected static void Father()
    {
        for (; ; )
        {
            empty.WaitOne();
            Console.WriteLine("爸爸放入一個蘋果");
            apple.Release();
        }
    }
    protected static void Mother()
    {
        for (; ; )
        {
            empty.WaitOne();
            Console.WriteLine("媽媽放入一個橘子");
            orange.Release();
        }
    }
    protected static void Daughter()
    {
        for (; ; )
        {
            apple.WaitOne();
            Console.WriteLine("女兒吃掉蘋果");
            empty.Release();
        }
    }
    protected static void Son()
    {
        for (; ; )
        {
            orange.WaitOne();
            Console.WriteLine("兒子吃掉橘子");
            empty.Release();
        }
    }
}

1.讀者寫者

讀寫,寫寫互斥 

https://blog.csdn.net/fobdddf/article/details/25769993

讀先

using System.Threading;
//讀者優先
//
namespace ReaderFirst
{
    class Program
    {
        private static int readCount = 0;//讀者數
        //rMutex:一個操作變量  mutex:一個文件區域
        private static Semaphore rMutex, mutex;
        static void Main(string[] args)
        {
            mutex = new Semaphore(1, 1);
            rMutex = new Semaphore(1, 1);
            Thread reader = new Thread(Reader);
            Thread writer = new Thread(Writer);
            writer.Start();
            reader.Start();
        }
        protected static void Reader()
        {
            while (true)
            {
                rMutex.WaitOne();
                readCount++;
                if (readCount==1)
                {
                    mutex.WaitOne();//讀進程只要看到有其他讀進程正在訪問文件,就可以繼續作讀訪問;
                }
                rMutex.Release();

                Console.WriteLine("");
                Thread.Sleep(100);

                rMutex.WaitOne();
                readCount--;
                if (readCount == 0)
                {
                    mutex.Release();
                }
                rMutex.Release();

            }
        }
        protected static void Writer()
        {
            while (true)
            {
                mutex.WaitOne();//寫進程必須等待所有讀進程都不訪問時才能寫文件,即使寫進程可能比一些讀進程更早提出申請。
                Console.WriteLine("");
                Thread.Sleep(100);
                mutex.Release();
            }
        }
    }
}

 

寫先

 

using System.Threading;
//寫者優先
//添加一個排隊信號量 queue。讀寫進程訪問文件前都要在此信號量上排隊
namespace WriterFirst
{
    class Program
    {//mutex --> access to file; rMutex --> access to readcount
        //wMutex --> access to writecount
        private static int readCount = 0, writeCount = 0;
        private static Semaphore rMutex,wMutex, mutex, queue;
        static void Main(string[] args)
        {
            rMutex = new Semaphore(1, 1);
            wMutex = new Semaphore(1, 1);
            mutex = new Semaphore(1, 1);
            queue = new Semaphore(1, 1);
            Thread reader = new Thread(Reader);
            Thread writer = new Thread(Writer);
            writer.Start();
            reader.Start();
        }
        protected static void Reader()
        {
            while (true)
            {
                //每個讀進程最開始都要申請一下 queue 信號量
                queue.WaitOne();
                rMutex.WaitOne();
                readCount++;
                if (readCount==1)
                {
                    mutex.WaitOne();
                }
                rMutex.Release();
                queue.Release();

                Console.WriteLine("");
                Thread.Sleep(100);

                rMutex.WaitOne();
                readCount--;
                if (readCount == 0)
                {
                    mutex.Release();
                }
                rMutex.Release();

            }
        }
        protected static void Writer()
        {
            while (true)
            {
                //只有第一個寫進程需要申請 queue,之后就一直占着不放了,直到所有寫進程都完成后才讓出。
                //等於只要有寫進程提出申請就禁止讀進程排隊
                wMutex.WaitOne();
                writeCount++;
                if (writeCount==1)
                {
                    queue.WaitOne();
                }
                wMutex.Release();

                mutex.WaitOne();
                Console.WriteLine("");
                Thread.Sleep(100);
                mutex.Release();

                wMutex.WaitOne();
                writeCount--;
                if (writeCount == 0)
                {
                    queue.Release();
                }
                wMutex.Release();
            }
        }
    }
}

 

公平

using System.Threading;
//讀寫公平  
namespace wrEqual
{
    class Program
    {//先申請一下 queue 信號量
        private static int readCount;
        private static Semaphore mutex, rMutex, queue;
        static void Main(string[] args)
        {
            mutex = new Semaphore(1, 1);
            rMutex = new Semaphore(1, 1);
            queue = new Semaphore(1, 1);
            Thread reader = new Thread(Reader);
            Thread writer = new Thread(Writer);
            writer.Start();
            reader.Start();
        }
        protected static void Reader()
        {
            while (true)
            {
                queue.WaitOne();
                rMutex.WaitOne();
                readCount++;
                if (readCount==1)
                {
                    mutex.WaitOne();
                }
                rMutex.Release();
                queue.Release();

                Console.WriteLine("");
                Thread.Sleep(100);

                rMutex.WaitOne();
                readCount--;
                if (readCount ==0)
                {
                    mutex.Release();
                }
                rMutex.Release();
            }
        }
        protected static void Writer()
        {
            while (true)
            {
                queue.WaitOne();
                mutex.WaitOne();
                Console.WriteLine("");
                Thread.Sleep(100);
                mutex.Release();
                queue.Release();
            }
        }
    }
}

 

生產者消費者

 https://blog.csdn.net/u011080413/article/details/18184187

  1. //如果empty與mutex的順序反了,就會發生死鎖!
using System.Threading;
//生產者生產數據,消費者也在緩沖區消耗這些數據。
//該問題的關鍵就是要保證生產者不會在緩沖區滿時加入數據,消費者也不會在緩沖區中空時消耗數據。
//假設緩沖區大小為10,生產者、消費者線程若干。 
namespace ProduConsum
{
    class Program
    {
        private static int[] buff = new int[10];
        static Random rand=new Random();
        private static Semaphore mutex, empty, full;
        static void Main(string[] args)
        {
            mutex = new Semaphore(1, 1);
            empty = new Semaphore(10, 10);//上來為空
            full = new Semaphore(0, 10);
            Thread producer = new Thread(Producer);
            Thread consumer = new Thread(Consumer);
            producer.Start();
            consumer.Start();
        }
        protected static void Producer()
        {
            int temp;
            uint pointer=0;
            while (true)
            {
                empty.WaitOne();
                mutex.WaitOne();
temp
= rand.Next(10);//生產者隨機,商品1-10 buff[pointer] = temp;//緩沖區1-10循環 Console.WriteLine("{0}生產者生產了{1}商品",temp,pointer); pointer = (pointer + 1) % 10;
mutex.Release(); full.Release();
//生產一個,消費一個 Thread.Sleep(100); } } protected static void Consumer() { int temp; uint pointer = 0; while (true) { full.WaitOne(); mutex.WaitOne();
temp
= buff[pointer]; Console.WriteLine("{0}消費者消費了{1}產品",temp,pointer); pointer = (pointer + 1) % 10;
mutex.Release(); empty.Release(); Thread.Sleep(
100); } } } }

 

 

using System.Threading;
//最簡單的情況:一個生產者,一個消費者,共用一個緩沖區進行生產消費。
namespace one2one
{
    class Program
    {
        private static Semaphore empty,full;
        static void Main(string[] args)
        {
            empty = new Semaphore(1, 1);//保證生產在前,消費在后
            full = new Semaphore(0, 1);
            Thread producer = new Thread(Producer);
            Thread consumer = new Thread(Consumer);
            producer.Start();
            consumer.Start();
        }
        protected static void Producer()
        {
            while (true)
            {
                empty.WaitOne();
                Console.WriteLine("生產");
                full.Release();
                Thread.Sleep(100);
            }
        }
        protected static void Consumer()
        {
            while (true)
            {
                full.WaitOne();
                Console.WriteLine("消費");
                empty.Release();
                Thread.Sleep(100);
            }
        }
    }
}

 

閱覽室問題

(本程序待定)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
//閱覽室100個座位 。判斷是否有座位 進入登記   出去 登出
//填寫登記表,一次一人  進入前判斷是否為滿
namespace library 
{
    class Program
    {
        private static Semaphore empty, full,mutex;
        static void Main(string[] args)
        {
            empty = new Semaphore(2, 2);//初始沒人
            full = new Semaphore(0, 2);//滿人
            mutex = new Semaphore(1, 1);//填表
            Thread goin = new Thread(Goin);
            Thread goout = new Thread(Goout);
            goin.Start();
            goout.Start();
        }
        protected static void Goin()
        {
            while (true)
            {
                empty.WaitOne();
                mutex.WaitOne();
                Console.WriteLine("登記");
                Thread.Sleep(100);
                mutex.Release();
                full.Release();
            }
        }
        protected static void Goout()
        {
            while (true)
            {
                full.WaitOne();
                mutex.WaitOne();
                Console.WriteLine("登出");
                Thread.Sleep(100);
                mutex.Release();
                empty.Release();
            }
        }
    }
}

 

using System.Threading;
namespace _10Thread
{
    class Program
    {
        private static int count=0;
        private static Semaphore empty = new Semaphore(10, 10);//控制總座位數
        private static Semaphore mutex = new Semaphore(1, 1);
        private static Random rand = new Random();
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Thread reader = new Thread(Reader);
                reader.Start();
            }
        }
        static void Reader()
        {
            while (true)
            {
                empty.WaitOne();
                mutex.WaitOne();
                count++;
                Console.WriteLine("登記,總人數:" + count);
                mutex.Release();

                mutex.WaitOne();
                count--;
                Console.WriteLine("登出,總人數:" + count);
                mutex.Release();
                empty.Release();
            }
            }
 
    }
}

 進程是資源分配的最小單位,線程是資源共享的最小單位,閱覽室提供100個座位,相當於一個進程有100個資源,線程(讀者)可以並發訪問進程的共享資源,實現對資源的計數操作


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM