C# 线程同步代码

#define CODE1

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SomeDemo
{
    public class AsyncDemo
    {
        public void Run()
        {
            MutexTest();
        }

        /// <summary>
        /// 线程间同步, 可以暂时释放锁
        /// TryEnter、Enter用于获取锁
        /// Exit用于释放锁
        /// Wait用于暂时释放锁,让其他线程获取锁
        /// Pulse用于唤醒处于wait状态的线程
        /// lock(obj) {...} 等效于 try { Monitor.Enter(obj, ref token); ...} finally { if (token) Monitor.Exit(obj); }
        /// </summary>
        private void MonitorTest()
        {
            var lck = new object();
            var token = false;
            var t1 = Task.Run(() =>
            {
                Output("1 start");
                Monitor.TryEnter(lck, 500, ref token);
                if (token)
                {
                    Output("1 Enter");
                    Thread.Sleep(3000);
                    Monitor.Wait(lck);
                    Output("1 wait end");
                    Monitor.Exit(lck);
                }
                else
                    Output("1 Pass");
                Output("1 end");
            });

            Thread.Sleep(100);//为了让t1先获取锁
            Output("2 start");
            lock (lck)
            {
                Output("Enter 2");
                Thread.Sleep(3000);
                Monitor.Pulse(lck);
                Output("2 pulse end");
                Thread.Sleep(3000);
            }
            Output("2 end");
            Task.WaitAll(t1);
        }

        /// <summary>
        /// 为多个线程共享的变量提供原子操作
        /// 为变更的加、减等操作提醒原子操作
        /// </summary>
        private void InterLockedTest()
        {
#if CODE1
            //计数demo
            int cnt = 0;
            var tt1 = new Task(() =>
            {
                for (int i = 0; i < 10000000; i++)
                    //lock(this)
                    {
                    Interlocked.Increment(ref cnt);
                        //cnt += 1;
                    }
            });
            var tt2 = new Task(() =>
            {
                for (int i = 0; i < 10000000; i++)
                    //lock(this)
                    {
                    Interlocked.Increment(ref cnt);
                        //cnt += 1;
                    }
            });
            var ms = GetRunTime(() =>
            {
                tt1.Start();
                tt2.Start();
                Task.WaitAll(tt1, tt2);
            });
            Console.WriteLine(ms + " " + cnt);
#else
            //用interlock保证只运行一次
            int flag = 0;
            var tasksWithoutInterLocked = Enumerable.Range(0, 1000000).Select(_i => new Task(() =>
            {
                if (flag != 0)
                    return;
                Thread.Sleep(1);//模拟时间差
                    flag = 1;
                Console.WriteLine("maybe one");
            })).ToArray();
            foreach (var t in tasksWithoutInterLocked)
                t.Start();
            Task.WaitAll(tasksWithoutInterLocked);
            Console.WriteLine("无InterLocked任务运行结束");

            flag = 0;
            var tasksWithInterLocked = Enumerable.Range(0, 1000000).Select(_i => new Task(() =>
            {
                if (0 == Interlocked.Exchange(ref flag, 1))
                    Console.WriteLine("only one");
            })).ToArray();
            foreach (var t in tasksWithInterLocked)
                t.Start();
            Task.WaitAll(tasksWithInterLocked);
            Console.WriteLine("InterLocked任务运行结束");
#endif
        }

        /// <summary>
        /// 用于在两个线程之间进行信号发送, 保证不同线程间的执行顺序
        /// 构造函数的 initialState 可以理解为门的状态,true表示门是开着的,false表示门的关闭的
        /// 调用waitone的时候如果门是打开状态就直接进门然后自动关门, 如果门是关闭状态则等门开后进入
        /// 调用Set表示开门, 然后第一个调用waitone的线程进入
        /// 调用Reset表示关门
        /// </summary>
        private void AutoResetEventTest()
        {
            var are = new AutoResetEvent(true);
            int loopTimes = 100;
            var t1 = Task.Run(() =>
            {
                for (int i = 0; i < loopTimes; i++)
                {
                    are?.WaitOne();
                    Output("1: " + i);
                    Thread.Sleep(1);
                    are?.Set();
                }
            });

            for (int i = 0; i < loopTimes; i++)
            {
                are?.WaitOne();
                Output("----2: " + i);
                Thread.Sleep(1);
                are?.Set();
            }
            Task.WaitAll(t1);
        }

        /// <summary>
        /// ManualResetEvent 基本与 AutoResetEvent 一致
        /// 区别在于 AutoResetEvent 在WaitOne 后自动调用 Reset, ManualResetEvent 需要手动调用Reset对WaitOne进行阻塞
        /// </summary>
        private void ManualResetEventTest()
        { }

        private void MethodImplAttributeTest()
        {
            var tasks = Enumerable.Range(0, 5).Select(_i => new Task(FuncWithMethidImpl)).ToArray();
            foreach (var t in tasks)
                t.Start();
            Task.WaitAll(tasks);
        }

        /// <summary>
        /// 整个方法上锁
        /// </summary>
        [MethodImpl(MethodImplOptions.Synchronized)]
        private void FuncWithMethidImpl()
        {
            Output("");
            Thread.Sleep(1000);
        }

        /// <summary>
        /// 读写锁
        /// 使用ReaderWriterLock进行资源访问时,如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时 刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待
        /// AcquireReaderLock / ReleaseReaderLock 用于申请/释放读锁
        /// AcquireWriterLock / ReleaseWriterLock 用于申请/释放写锁
        /// </summary>
        private void ReaderWriterLockTest()
        {
            var lck = new ReaderWriterLock();

            var funcRead = new Action(() =>
            {
                lck.AcquireReaderLock(int.MaxValue);
                Output("read lock get");
                Thread.Sleep(2000);
                Output("read lock release");
                lck.ReleaseReaderLock();
            });

            var funcWrite = new Action(() =>
            {
                Thread.Sleep(5);//为了让读锁先获取
                lck.AcquireWriterLock(int.MaxValue);
                Output("write lock get");
                Thread.Sleep(2000);
                Output("write lock release");
                lck.ReleaseWriterLock();
            });

            var tr1 = new Task(funcRead);
            var tr2 = new Task(funcRead);
            var tr3 = new Task(funcRead);
            var tw1 = new Task(funcWrite);
            var tw2 = new Task(funcWrite);

            //先申请两个读锁再申请两个写锁再申请一个读锁
            tr1.Start();
            tr2.Start();
            tw1.Start();
            tw2.Start();
            Thread.Sleep(100);
            tr3.Start();

            Task.WaitAll(tr1, tr2, tr3, tw1, tw2);
        }

        /// <summary>
        /// 互斥锁,可用于进程间同步
        /// 构造函数的 name 在操作系统中唯一
        /// WaitOne加锁
        /// ReleaseMutex解锁
        /// WaitOne的执行次数和ReleaseMutex一定要一致
        /// </summary>
        private void MutexTest()
        {
            using (var mutex = new Mutex(true, "whosyourdaddy", out bool isNew))
            {
                if (isNew)
                    Console.WriteLine("启动成功, 任意键退出");
                else
                {
                    Console.WriteLine("启动失败, 等待其他程序退出");
                    mutex.WaitOne();
                    Console.WriteLine("启动成功, 任意键退出");
                }
                Console.ReadKey();
                mutex.ReleaseMutex();
            }
        }

        /// <summary>
        /// 信号量, 用来控制同时访问某个特定资源的操作数量,可用于进程间同步
        /// WaitOne、Release
        /// </summary>
        private void SemaphoreTest()
        {
            using (Semaphore sem = new Semaphore(3, 3, "greedisgood"))
            {
                Console.WriteLine("start");
                sem.WaitOne();
                Console.WriteLine("enter");
                Console.ReadKey();
                sem.Release();
                Console.WriteLine("exit");
            }
        }

        private void Output(string msg)
        {
            Console.WriteLine(DateTime.Now.ToString("mm:ss.fff") + ": " + msg);
        }

        private long GetRunTime(Action action)
        {
            var watch = Stopwatch.StartNew();
            action();
            watch.Stop();
            return watch.ElapsedMilliseconds;
        }
    }
}

原文地址:https://www.cnblogs.com/onestow/p/12026509.html

时间: 2024-11-02 03:09:06

C# 线程同步代码的相关文章

多线程之:线程同步代码块

java中使用关键字synchronized进行线程同步,有四中同步块: 1.实例方法 2.静态方法 3.实例方法中的同步块 4.静态方法中的同步块 实例方法同步:在方法申明中使用synchronized 关键字,同步在拥有该方法的对象上 1 public synchronized void increase(){ 2 this.id++; 3 } 静态方法同步:与实例方法同步一样,在方法申明中使用synchronized 关键字,同步在拥有该方法的类对象上,同时只允许一个线程执行同一个类中的静

几组线程同步代码测试

1. public class A { public void MA() { lock (typeof(A)) { Thread.Sleep(5000); Console.WriteLine("MA:" +DateTime.Now); } } public void MB() { Thread.Sleep(100); Console.WriteLine("MB:" + DateTime.Now); } } } private void button4_Click(o

IOS 多线程,线程同步的三种方式

一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IOS中我们一般情况下使用以下三种线程同步代码方式: 第一种和第二种代码同步的使用方法,一般情况下我们只需要使用NSLock和NSCondition申明2个属性.然后给此属性赋对应的值.那么即可作为安全防控的线程手段. 同时也可以保证线程的资源安全. 1:NSLock方式 [xxxlock   lock] //上锁 同步代码块 [xxxlock   unlock]//解锁 2:NSCondition

mfc小工具开发之定时闹钟之---多线程急线程同步

一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等.用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等.但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务. 在MFC中,一般用全局函数Afx

使用Win32 API实现生产者消费者线程同步

使用win32 API创建线程,创建信号量用于线程的同步 创建信号量 语法例如以下 HANDLE semophore; semophore = CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); CreateSemophore函数的原型例如以下: HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreA

Visual C++线程同步技术剖析:临界区,事件,信号量,互斥量

转自: 使线程同步 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解.正常情况下对这种处理结果的了解应当在其处理任务完成后进行. 如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解.例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题.如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数

【java并发】(2) Java线程同步:synchronized锁住的是代码还是对象

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在方法上. 关键是,不要认为给方法或者代码段加上synchronized就万事大吉,看下面一段代码: class Sync { public synchronized void test() { System.out.println("test开始.."); try { Thread.sle

【编写高质量代码C#】建议72:在线程同步中使用信号量

1.使用信号机制提供线程同步的一个简单例子 AutoResetEvent autoResetEvent = new AutoResetEvent(false); private void button1_Click(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; Thread tWork = new Thread(() => { label1.Text = "线程启动...&quo

Java线程安全与同步代码块

因为在电商网站工作的原因,对于秒杀.闪购等促销形式相当熟悉.无外乎商家拿出一定量的库存去做所谓的"亏本买卖",其目的是用有限的库存去吸引无限的流量.然而,我却碰到过因为系统问题,导致秒杀品超卖的情况.可怜的商户其实只提供了10双9.9元的童鞋做秒杀,却在瞬间内卖出了1000双! 类似这样的问题,在非线程安全的程序设计中十分常见,我们下面运行一个秒杀的程序: public class SalesThread implements Runnable { private int stock