博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程同步技术(一)
阅读量:4709 次
发布时间:2019-06-10

本文共 5522 字,大约阅读时间需要 18 分钟。

多线程编程过程中,难免会涉及到资源共享的问题,在并发的线程中,如果不对线程加以控制,线程抢夺共享资源,对资源的读取和修改混乱,结果会导致不是我们想要的结果,这就需要引入线程同步的技术。

先演示下没有同步技术的案例:

class ThreadTT    {        int counter = 0;        public void LockTest()        {            Thread t1 = new Thread(new ParameterizedThreadStart(Run));            Thread t2 = new Thread(new ParameterizedThreadStart(Run));            Thread t3 = new Thread(new ParameterizedThreadStart(Run));            t1.Start("t1");            t2.Start("t2");            t3.Start("t3");        }        public void Run(object id)        {                for (int i = 0; i < 100; i++)                {                    counter++;                    Thread.Sleep(100);                    counter--;                    Console.WriteLine("{0} counter {1}", id, counter);                }        }    }

当执行LockTest() 方法之后,打印出的counter的值则是错乱的:

下面开始引入同步技术:

1.LOCK

class ThreadTT    {        int counter = 0;        public void LockTest()        {            Thread t1 = new Thread(new ParameterizedThreadStart(Run));            Thread t2 = new Thread(new ParameterizedThreadStart(Run));            Thread t3 = new Thread(new ParameterizedThreadStart(Run));            t1.Start("t1");            t2.Start("t2");            t3.Start("t3");        }        private  object obj = new object();        public void Run(object id)        {            lock (obj)            {                for (int i = 0; i < 100; i++)                {                    counter++;                    Thread.Sleep(100);                    counter--;                    Console.WriteLine("{0} counter {1}", id, counter);                }            }        }    }

再运行LockTest :

现在counter每次都只有一个线程占用;

2.Monitor

class ThreadTT    {        int counter = 0;        public void LockTest()        {            Thread t1 = new Thread(new ParameterizedThreadStart(Run));            Thread t2 = new Thread(new ParameterizedThreadStart(Run));            Thread t3 = new Thread(new ParameterizedThreadStart(Run));            t1.Start("t1");            t2.Start("t2");            t3.Start("t3");        }        private static  object obj = new object();        public void Run(object id)        {            Monitor.Enter(obj);                for (int i = 0; i < 10; i++)                {                    counter++;                    Thread.Sleep(100);                    counter--;                                        Console.WriteLine("{0} counter {1}", id, counter);                }           Monitor.Exit(obj);        }    }

 

Monitor.Wait() 释放线程锁,并阻塞线程,直到重新获取锁,否则之后的代码不再执行;

Monitor .pulse() 通知正在准备的线程,可以获取线程锁;

static void Main()        {            object obj = new object();            Thread t1 = new Thread(()=> {                Monitor.Enter(obj);                Console.WriteLine("t1 enter");                Console.WriteLine("t1.dosomething");                Monitor.Wait(obj);                Thread.Sleep(2000);                Console.WriteLine("t1 重新获取锁obj");                Monitor.Pulse(obj);                Monitor.Exit(obj);                Console.WriteLine("t1 exit");            });            Thread t2 = new Thread(()=> {                Monitor.Enter(obj);                                Console.WriteLine("t2 enter");                Monitor.Pulse(obj);                Console.WriteLine("t2 puslse");                Monitor.Wait(obj);                Console.WriteLine("t2 重新获取obj");                Monitor.Exit(obj);                Console.WriteLine("t2 exit");            });            t1.Start();            t2.Start();            Console.Read();        }

程序执行,首先进入t1,执行到Monitor.Wait(obj); 线程t1释放锁,并阻塞,开始进入线程t2,执行到Monitor.Wait(obj),线程t2阻塞,线程t1重新获取锁  执行到结束,并释放信号,t2接收到信号,继续执行结束

Monitor.Wait(obj,3000);

当前线程阻塞,等待3s钟,如果没有获取到锁,则继续执行下去

3.Mutex互斥锁

Mutex对象是一个同步基元,可以用来做线程间的同步。

若多个线程需要共享一个资源,可以在这些线程中使用Mutex同步基元。当某一个线程占用Mutex对象时,其他也需要占用Mutex的线程将处于挂起状态,Mutex 通常处于空闲状态,线程在使用的时候通过waitone()来获取一个可用的互斥,如果有,则获取互斥权限,执行线程,如果没有,则阻塞在那里直到等到信号;

private static Mutex mut = new Mutex();        private const int numIterations = 1;        private const int numThreads = 3;        static void Main()        {            for (int i = 0; i < numThreads; i++)            {                Thread newThread = new Thread(new ThreadStart(ThreadProc));                newThread.Name = String.Format("Thread{0}", i + 1);                newThread.Start();            }            Console.Read();        }        private static void ThreadProc()        {            for (int i = 0; i < numIterations; i++)            {                UseResource();            }        }        // This method represents a resource that must be synchronized        // so that only one thread at a time can enter.        private static void UseResource()        {            // Wait until it is safe to enter.            Console.WriteLine("{0} is requesting the mutex",                              Thread.CurrentThread.Name);            mut.WaitOne();            Console.WriteLine("{0} has entered the protected area",                              Thread.CurrentThread.Name);            // Place code to access non-reentrant resources here.            // Simulate some work.            Thread.Sleep(500);            Console.WriteLine("{0} is leaving the protected area",                Thread.CurrentThread.Name);            // Release the Mutex.           mut.ReleaseMutex();            Console.WriteLine("{0} has released the mutex",                Thread.CurrentThread.Name);        }

这里可以很清楚的看到,mutex每次只被一个线程占用,只有释放之后,另外的线程才可以进入;

转载于:https://www.cnblogs.com/yeshuimaowei/p/7458772.html

你可能感兴趣的文章
项目开源-基于ASP.NET Core和EF Core的快速开发框架
查看>>
UVA 580 - Critical Mass(简单DP)
查看>>
iOS应用日志:开始编写日志组件与异常日志
查看>>
Linux通过NFS实现文件共享
查看>>
java安装1.8和1.7,报错:Error: Registry key 'Software\JavaSoft\Java Runtime Environment'\CurrentVers...
查看>>
iOS多线程编程之NSOperation和NSOperationQueue的使用(转自容芳志专栏)
查看>>
svn不能添加.a文件的解决方法
查看>>
15模块-Maps【管理地图控件】
查看>>
[转]crontab命令指南
查看>>
vue 二级列表折叠面板
查看>>
ClientValidationEnabled
查看>>
Linux 硬盘分区、分区、删除分区、格式化、挂载、卸载
查看>>
Jam - an open-source build system
查看>>
编写一个程序,将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad。...
查看>>
Mysql命令大全
查看>>
nginx.conf 基础配置
查看>>
centos创建文件命令
查看>>
【php】 php能做什么
查看>>
VTK初学一,比较常见的错误2
查看>>
结队-贪吃蛇-项目进度
查看>>