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个资源,线程(读者)可以并发访问进程的共享资源,实现对资源的计数操作

优质内容筛选与推荐>>
1、Python timeit模块
2、[TimLinux] JavaScript 如何在html标签的data-*属性使用JSON数据
3、static关键字
4、oracle sql
5、poj1155 TELE(树形dp)


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn