zoukankan      html  css  js  c++  java
  • C#多线程技术总结(同步)

    二、串行(同步):
    
    1.lock、Monitor--注意锁定的对象必需是引用类型(string类型除外)
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
            private static object syncObject = new object();
     
            private static void TaskWork(object i)
            {
                Console.WriteLine("我是任务:{0}",i);
                lock (syncObject)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("我是任务:{0},线程ID:{1}",i,Thread.CurrentThread.ManagedThreadId);
                }
     
                try
                {
                    Monitor.Enter(syncObject);
                    Console.WriteLine("我是任务:{0},线程ID:{1}", i, Thread.CurrentThread.ManagedThreadId);
                }
                finally
                {
                    Monitor.Exit(syncObject);
                }
            }
     
    //调用
    Task.Factory.StartNew(TaskWork,1);
    Task.Factory.StartNew(TaskWork, 2);
    2.Interlocked
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int i=1;
    Interlocked.Increment(ref i); //增量+1=2;
    Console.WriteLine("i当前的值:{0}", i);
     
    Interlocked.Decrement(ref i); //减量-1=0;
    Console.WriteLine("i当前的值:{0}", i);
     
    Interlocked.Exchange(ref i, 2);//赋值=2;
    Console.WriteLine("i当前的值:{0}",i);
     
    Interlocked.CompareExchange(ref i, 10, 2);//比较交换值,当i=2时,则将i赋值为10;
    Console.WriteLine("i当前的值:{0}", i);
    3.Mutex--可以实现进程间的同步,甚至是两个远程进程间的同步
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var t1 = new Task(() =>
    {
        Console.WriteLine("我是第一个任务!");
        Mutex m = new Mutex(false, "test");
        m.WaitOne();
        Console.WriteLine("第一个任务完成!");
        m.ReleaseMutex();
    });
     
    var t2 = new Task(() =>
    {
        Console.WriteLine("我是第二个任务!");
        Mutex m = new Mutex(false, "test");
        m.WaitOne();
        Console.WriteLine("第二个任务完成!");
        m.ReleaseMutex();
    });
     
    t1.Start();
    t2.Start();
     4.ReaderWriterLock 、ReaderWriterLockSlim--如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待. 
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
        static ReaderWriterLock rwLock = new ReaderWriterLock();
     
        static void Read(object state)
        {
            Console.WriteLine("我是读线程,线程ID是:{0}",Thread.CurrentThread.ManagedThreadId);
            rwLock.AcquireReaderLock(Timeout.Infinite);//无限期等待,需要显式调用ReleaseReaderLock释放锁
            var readList = state as IEnumerable<int>;
            foreach (int item in readList)
            {
                Console.WriteLine("读取当前的值为:{0}", item);
                Thread.Sleep(500);
            }
            Console.WriteLine("读完成,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
            rwLock.ReleaseReaderLock();
             
        }
     
     
        static void Write(object state)
        {
            Console.WriteLine("我是写线程,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
            rwLock.AcquireWriterLock(Timeout.Infinite); //无限期等待,需要显式调用ReleaseWriterLock释放锁
            var writeList = state as List<int>;
            int lastCount=writeList.Count();
            for (int i = lastCount; i <= 10+lastCount; i++)
            {
                writeList.Add(i);
                Console.WriteLine("写入当前值:{0}",i);
                Thread.Sleep(500);
            }
            Console.WriteLine("写完成,线程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
            rwLock.ReleaseWriterLock();
        }
     
    //调用:
            var rwList = new List<int>();
     
            var t1 = new Thread(Write);
            var t2 = new Thread(Read);
            var t3 = new Thread(Write);
            var t4 = new Thread(Read);
             
            t1.Start(rwList);
            t2.Start(rwList);
            t3.Start(rwList);
            t4.Start(rwList);
     
    
    5.SynchronizationAttribute--确保某个类的实例在同一时刻只能被一个线程访问,类的定义要求:A.类上必需标记SynchronizationAttribute特性,B.类必需继承自System.ContextBoundObject对象
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
        [Synchronization(SynchronizationAttribute.REQUIRED,true)]
        public class Account : System.ContextBoundObject
        {
            private static int _balance;
            public int Blance
            {
                get
                {
                    return _balance;
                }
            }
     
            public Account()
            {
                _balance = 1000;
            }
     
            public void WithDraw(string name,object money)
            {
                if ((int)money <= _balance)
                {
                    Thread.Sleep(2000);
                    _balance = _balance - (int)money;
                    Console.WriteLine("{0} 取钱成功!余额={1}", name, _balance);
                }
                else
                {
                    Console.WriteLine("{0} 取钱失败!余额不足!", name);
                }
            }
        }
     
    //调用:
                var account = new Account();
                Parallel.Invoke(() =>
                {
                    account.WithDraw("张三",600);
     
                }, () =>
                {
                    account.WithDraw("李四",600);
                });
    6.MethodImplAttribute--使整个方法上锁,直到方法返回,才释放锁
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
        public class Account
        {
            private static int _balance;
            public int Blance
            {
                get
                {
                    return _balance;
                }
            }
     
            public Account()
            {
                _balance = 1000;
            }
     
            [MethodImpl(MethodImplOptions.Synchronized)]
            public void WithDraw(string name,object money)
            {
                if ((int)money <= _balance)
                {
                    Thread.Sleep(2000);
                    _balance = _balance - (int)money;
                    Console.WriteLine("{0} 取钱成功!余额={1}", name, _balance);
                }
                else
                {
                    Console.WriteLine("{0} 取钱失败!余额不足!", name);
                }
            }
        }
     
    //调用
                var account = new Account();
                Parallel.Invoke(() =>
                {
                    account.WithDraw("张三",600);
     
                }, () =>
                {
                    account.WithDraw("李四",600);
                });
    7.AutoResetEvent、ManualResetEvent、ManualResetEventSlim--调用WaitOne、WaitAny或WaitAll来使线程等待事件,调用Set方法发送信号,事件将变为终止状态,等待的线程被唤醒
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    AutoResetEvent arEvent = new AutoResetEvent(false);//默认为无信号,处于非终止状态
    Task.Factory.StartNew((o) => {
        for (int i = 1; i <= 10; i++)
        {
            Console.WriteLine("循环第{0}次",i);
        }
        arEvent.Set();//发送信号,处于终止状态
    },arEvent);
     
     
    arEvent.WaitOne();//等待信号,收到信号后则继续下面的执行
     
    Console.WriteLine("我是主线程,我继续执行!");
    Console.Read();
     8.Sempaphore、SemaphoreSlim(不可跨进程)--信号量,可实现线程、进程间同步
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
        public class WashRoom
        {
            private readonly Semaphore sem;
     
            public WashRoom(int maxUseableCount)
            {
                sem = new Semaphore(maxUseableCount, maxUseableCount, "WC");
            }
     
            public void Use(int i)
            {
                Task.Factory.StartNew(() =>
                    {
                        Console.WriteLine("第{0}个人等待进入", i);
                        // WaitOne:如果还有“空位”,则占位,如果没有空位,则等待;
                        sem.WaitOne();
                        Console.WriteLine("第{0}个人成功进入,使用中", i);
                        // 模拟线程执行了一些操作
                        Thread.Sleep(100);
                        Console.WriteLine("第{0}个人用完,离开了", i);
                        // Release:释放一个“空位”
                        sem.Release();
                    });
            }
        }
     
    //调用:
                var wc = new WashRoom(5);
                for (int i = 1; i <= 7; i++)
                {
                    wc.Use(i);
                }
    9.Barrier--屏障,使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作,即:将一个阶段的事情分成多个线程来异步执行,执行完毕后再同时进入下一个阶段
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    int taskSize = 5;
    Barrier barrier = new Barrier(taskSize, (b) =>
    {
        Console.WriteLine(string.Format("{0}当前阶段编号:{1}{0}", "-".PadRight(15, '-'), b.CurrentPhaseNumber));
    });
     
    var tasks = new Task[taskSize];
     
    for (int i = 0; i < taskSize; i++)
    {
        tasks[i] = Task.Factory.StartNew((n) =>
        {
            Console.WriteLine("Task : #{0}   ---->  处理了第一部份数据。", n);
            barrier.SignalAndWait();
     
            Console.WriteLine("Task : #{0}   ---->  处理了第二部份数据。", n);
            barrier.SignalAndWait();
     
            Console.WriteLine("Task : #{0}   ---->  处理了第三部份数据。", n);
            barrier.SignalAndWait();
     
        }, i);
    }
     
    Task.WaitAll(tasks);
    10.SpinLock--自旋锁,仅限锁定的时间较短
    
    示例:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
                SpinLock sLock = new SpinLock();
                int num = 0;
                Action action = () =>
                {
                    bool lockTaken = false;
                    for (int i = 0; i < 10; i++)
                    {
                        lockTaken = false;
                        try
                        {
                            sLock.Enter(ref lockTaken);
                            Console.WriteLine("{0}+1={1} ---线程ID:[{2}]", num, ++num,Thread.CurrentThread.ManagedThreadId);
                            Thread.Sleep(new Random().Next(9));
                        }
                        finally
                        {
                            //真正获取之后,才释放
                            if (lockTaken) sLock.Exit();
                        }
                    }
                };
     
    //多线程调用:
                Parallel.Invoke(action, action, action);
                Console.WriteLine("合计:{0}", num);
    11.SpinWait--自旋等待,轻量级
    
    1
    2
    3
    4
    5
    6
    7
    8
    Thread.Sleep(1000);//线程等待1S;
    Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
     
    SpinWait.SpinUntil(() => false, 1000);//自旋等待1S
    Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
     
    Thread.SpinWait(100000);//指定CPU的循环次数,时间间隔处决于处理器的运行速度,一般不建议使用
    Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    12.CountdownEvent--与Sempaphore功能类似,但CountdownEvent支持动态调整信号计数
    
     示例:
    
            static void TimeLimitShopping(int custCount,int times,CountdownEvent countdown)
            {
                var customers = Enumerable.Range(1, custCount);
                foreach (var customer in customers)
                {
                    int currentCustomer = customer;
                   Task.Factory.StartNew(()=>
                    {
                        SpinWait.SpinUntil(() => false, 1000);
                        Console.WriteLine("第{0}波客户购买情况:Customer-{1}-已购买.", times, currentCustomer);
                        countdown.Signal();
                    });
                    //countdown.AddCount();
                }
            }
     
     
    //调用:
    var countdown = new CountdownEvent(5);
                    TimeLimitShopping(5, 1, countdown);
                    countdown.Wait();
     
     
                    countdown.Reset(10);
                    TimeLimitShopping(10, 2, countdown);
                    countdown.Wait();
     
                    countdown.Reset(20);
                    TimeLimitShopping(20, 3, countdown);
                    countdown.Wait();
     最后分享在System.Collections.Concurrent命名空间下的几个并发集合类:
    
    ConcurrentBag<T>:表示线程安全的无序集合;
    
    ConcurrentDictionary<T>:表示线程安全的多个键值对集合;
    
    ConcurrentQueue<T>:表示线程安全的先进先出集合;
    
    ConcurrentStack<T>:表示线程安全的后进先出集合;
    
    线程的几个状态(以下图片来源于这篇文章:http://www.cnblogs.com/edisonchou/p/4848131.html):
  • 相关阅读:
    VMware虚拟机的三种连接方式
    Codeblocks16.01配置wxWidgets3.0.4
    DAO编程(VC6.0中的应用)
    VC++ 中用ado连接数据库
    C中文件的输入输出与C++的文件流
    Cpp中流继承关系
    a标签置灰不可点击
    手动操作数据库
    $.ajaxFileUpload is not a function
    【工具】手机号码、电话号码正则表达式
  • 原文地址:https://www.cnblogs.com/profession/p/5511854.html
Copyright © 2011-2022 走看看