IT知识库 购物 网址 游戏 小说 歌词 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> .NET新手区 -> 多线程编程学习笔记——线程同步(一) -> 正文阅读

[.NET新手区]多线程编程学习笔记——线程同步(一)

多线程编程学习笔记——线程同步(一) 接上文 多线程编程学习笔记-基础(一) 接上文 多线程编程学习笔记-基础(二) 接上文 多线程编程学习笔记-基础(三)
      就如上一篇文章(多线程编程学习笔记-基础(三))中的示例代码十,一样如果多线程使用共享变量,就会涉及到一个线程同步的问题。那如何解决呢?
    方法有三:
1)        重构程序,移除多线程的共享变量,让一个线程只访问一个自有变量
2)        使用原子操作,一个操作只占用一个量子时间,一次完成,只有当当前操作完成之后,其他线程才能进行操作。这样可以避免使用独占锁,避免死锁。
3)        通过NET构架提供的Mutex、AutoRestEvent、CountDownEven、SpinWait等类,来进行线程间的同步。
一、使用InterLocked类
        在上一篇文章中,我们使用lock来解决多线程访问带来的问,而在这里我们使用InterLocked类提供的原子操作,从而帮助我们不需要使用lock锁来锁定,以免造成死锁。
       接下来我们改造一下上一篇文章中的代码,代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics;
 

namespace ThreadSynchronousDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("开始,InterLocked 同步");
            var c = new Counter();
            Thread t = new Thread(() => Count(c));
            var t3 = new Thread(() => Count(c));

            var t2 = new Thread(() => Count(c));
            t.Name = "线程1"; 

            //启动线程
            t.Start();
            t2.Name = "线程2";
            t2.Start();
 

            t3.Name = "线程3";
            t3.Start();
            t.Join();
            t2.Join();
            t3.Join();
            Console.WriteLine(string.Format("没有加锁的多线程总计:{0}", c.Count));
            Console.WriteLine("----------------------------");
            var c1 = new CounterInterLocked();
            var t4 = new Thread(() => Count(c1));
            t4.Name = "线程4";
 

            var t5 = new Thread(() => Count(c1));
            t5.Name = "线程5";
            var t6 = new Thread(() => Count(c1));

            t6.Name = "线程6";
            t4.Start();
            t5.Start();
            t6.Start();
            t4.Join();
            t5.Join();
            t6.Join();
            Console.WriteLine(string.Format("InterLocked的多线程总计:{0}", c1.Count));
            Console.Read();
        }

        static void Count(CountBase cnt)
        {
            for (int i = 0; i < 100000; i++)
            {
                cnt.Incerement();
                cnt.Dncerement();
            }
        }
    }

    abstract class CountBase
    {
        public abstract void Incerement();
        public abstract void Dncerement();
    }
    class Counter : CountBase
    {
        public int Count { get; private set; }
        public override void Dncerement()
        {
            Count--;
        }
        public override void Incerement()
        {
            Count++;
        }
    }

    class CounterInterLocked : CountBase
    {
        private int m_count;
        public int Count { get { return m_count; } }
        public override void Dncerement()
        {

            Interlocked.Decrement(ref m_count);
        }
        public override void Incerement()
        {

            Interlocked.Increment(ref m_count);
        }
    }
}

此程序运行结果如下图,跟上一篇中的示例十,结果是一样的。只是代码上的区别。
 

二、使用Mutex类
1. 接下来我们来学习使用Mutex类来实现线程间的同步问题。
2. 在程序启动时,设置InitialOwner为false,这表示如果互斥量已经建立,则允许程序获取互斥量。如果没有互斥量,则程序直接运行,等待接收任意键,然后释放互斥量。
3.代码如下: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics;

namespace ThreadSynchronousDemo
{
    class Program
    {
        const string mutexName = "syncMutex";
        static void Main(string[] args)
        {
            Console.WriteLine("开始,Mutex 同步");
            using (var mut=new Mutex(false,mutexName))
            {
                if (!mut.WaitOne(TimeSpan.FromSeconds(5),false))
                {
                    Console.WriteLine("等待5秒之后运行。。。。");
                }
                else
                {
                    Console.WriteLine("正在运行。。。。,请输入任意键");
                    Console.ReadLine();
                    mut.ReleaseMutex();
                    Console.WriteLine("释放互斥量");

                }
            }         

            Console.Read();

        }
    }
}

 

4.运行结果如下图。
 

        在debug目录下,先运行主程序,如上图中1,则程序1正常运行,此时如果再次打开Debug目录下的应用主程序,则运行结果如上图中2。说明互斥量起作用了。
5.先在上图主程序1中输入k,然后回车,结果如下图中3。我们从Debug目录下,再次打开应用程序,则应用程序的运行结果如下图中4。说明主程序1,已经把互斥量释放。
 

       注意:具名互斥量是全局的操作系统对象。请务必正确关闭互斥量。最好使用using来包裹互斥量代码。这种方式可以在不同程序中同步线程。
三、使用SemaphoreSlim类
       SemaphoreSlim是Semaphore类的一个轻量级版本。此类限制了同时访问同一资源的线程数量。
        在.net中,类Semaphore封装了CLR中的内核同步对象。与标准的排他锁对象(Monitor,Mutex,SpinLock)不同的是,它不是一个排他的锁对象,它与SemaphoreSlim,ReaderWriteLock等一样允许多个有限的线程同时访问共享内存资源。
        Semaphore就好像一个栅栏,有一定的容量,当里面的线程数量到达设置的最大值时候,就没有线程可以进去。然后,如果一个线程工作完成以后出来了,那下一个线程就可以进去了。Semaphore的WaitOne或Release等操作分别将自动地递减或者递增信号量的当前计数值。当线程试图对计数值已经为0的信号量执行WaitOne操作时,线程将阻塞直到计数值大于0。在构造Semaphore时,最少需要2个参数。信号量的初始容量和最大的容量。
 1.程序代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics; 

namespace ThreadSynchronousDemo
{
    class Program
    {
        static SemaphoreSlim semapSlim = new SemaphoreSlim(5);
        static void Main(string[] args)
        {
            Console.WriteLine("开始,SemaphoreSlim 同步");
            for (int i = 1; i < 9; i++)
            {
                string threadName = "线程 " + i;
                int seconds = new Random().Next(1, 10);
                var t = new Thread((() => AccessDatabase(threadName, seconds)));
                t.Start();
            }
            Console.Read();
        }

        static void AccessDatabase(string name,int seconds)
        {
            Console.WriteLine("{0} 等待访问数据库", name);
            semapSlim.Wait();
            Console.WriteLine("{0} 被授予对数据库的访问权限", name);
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine("{0} 完成了", name);
            semapSlim.Release();          

        }
    }
}

2.程序运行结果如下图。
 

       当程序启动时,创建了一个SemaphoreSlim对象,并在构造函数中指定了并发的线程数量,然后启动了10个不同名称,不同初始运行时间的线程。
        每个线程都尝试获取数据库访问权限,但是我们使用SemaphoreSlim对象做了限制,只有5个线程能同时访问数据库,当前5个线程获取了数据库访问权限之后,剩下的5个线程只能等待,直到有线程完成工作,并调用Semaphore的Release方法。
上一篇文章      下一篇文章      查看所有文章
加:2017-10-27 23:21:56  更:2017-10-27 23:22:01 
 
  .NET新手区 最新文章
将ZIP文件添加到程序集资源文件然后在运行时
Web服务的调用
.NET创建WebService服务简单的例子
多线程编程学习笔记——任务并行库(三)
序列化和反序列化
Spring学习之路
cs代码实现控件移动TranslateTransform
Asp.net基础知识
ACdream原创群赛(11)の风神日华神专场C.神奇
SQL 存储和触发器
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 新闻资讯 小游戏 Chinese Culture 股票 三丰软件 开发 中国文化 网文精选 阅读网 看图 日历 万年历 2018年10日历
2018-10-24 3:22:43
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库