文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C#中AutoResetEvent控制线程用法小结

2024-04-02 19:55

关注

本文主要来自一道面试题,由于之前对AutoResetEvent的概念比较模糊(即使已经使用过了)。面试题题目很简洁:两个线程交替打印0~100的奇偶数。你可以先动手试试,我主要是尝试在一个方法里面完成这个任务。

注: Suspend,Resume来控制线程已经在.net framework2.0被淘汰了,原因就是挂起之后,但因为异常而没有及时恢复,如果占用资源会导致死锁。

AutoResetEvent主要方法及实践

有了上面的解释,开始展示代码(经过多次优化)

 //若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false
        static AutoResetEvent oddResetEvent = new AutoResetEvent(false);
        static AutoResetEvent evenResetEvent = new AutoResetEvent(false);
        static int i = 0;
        static void Main(string[] args)
        {
            //ThreadStart是个委托
            Thread thread1 = new Thread(new ThreadStart(show));
            thread1.Name = "偶数线程";
            Thread thread2 = new Thread(new ThreadStart(show));
            thread2.Name = "奇数线程";
            thread1.Start();
           Thread.Sleep(2); //保证偶数线程先运行。
            thread2.Start();
            Console.Read();

        }
        public static void show()
        {
             while (i <= 100)
            {
                int num = i % 2;
                if (num == 0)
                {
                    Console.WriteLine("{0}:{1} {2}  ", Thread.CurrentThread.Name, i++, "evenResetEvent");
                    if(i!=1) evenResetEvent.Set(); 
                    oddResetEvent.WaitOne(); //当前线程阻塞
                   
                }
               else
                {  
                    Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, "oddResetEvent");
                    //如果此时AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。否则不会被阻止
                     oddResetEvent.Set();
                    evenResetEvent.WaitOne();
                }
            }
        }

结果如下图所示:

注意点:
不要有一点点点点多余的evenResetEvent.Set(),他会让后续的 evenResetEvent.WaitOne();失效.

第二种方法Semaphore

此外,我们利用信号量也可以实现,信号量是一种内核模式锁,对性能要求比较高,特殊情况下才考虑使用,而且要避免在内核模式和用户模式下频繁相互切换线程。代码如下:

 private static readonly int MaxSize = 1;
        private static int i = 0;
        static Semaphore oddSemaphore = new Semaphore(0, MaxSize);
        static Semaphore evenSemaphore = new Semaphore(0, MaxSize);

        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            //ThreadStart是个委托
            Thread thread1 = new Thread(new ThreadStart(show));
            thread1.Name = "偶数线程";
            Thread thread2 = new Thread(new ThreadStart(show));
            thread2.Name = "奇数线程";
            thread1.Start();
            thread2.Start();
            thread1.Join();
            stopwatch.Stop();
            Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
            Console.Read();
        }

        private static void show()
        {
            if(i==1) evenSemaphore.WaitOne();
            while (i <= 100)
            {
                int num = i % 2;
                if (num == 0)
                {
                    Console.WriteLine("{0}:{1}  {2}    ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
                    evenSemaphore.Release();
                    oddSemaphore.WaitOne(); //当前线程阻塞
                }
                else
                {
                    Console.WriteLine("{0}:{1}  {2}    ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
                    //释放一个偶数信号空位出来;
                    oddSemaphore.Release();
                    evenSemaphore.WaitOne(); //当前线程阻塞
                    //此时已经消耗了一个奇数信号空位
                }
            }
        }

第三种方法,约定每个线程只干自己的事

这种方法利用线程池本身就是队列的方式,即先进先出。测试之后发现性能有下降,但是还是贴出来供参考。

      static int threadCount = 2;
        static int count = 0;
        static object cursorLock = new object();
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            Task[] arr = new Task[2];
            for (int threadIndex = 0; threadIndex < threadCount; threadIndex++)
            {
                //这两种方法都可以
                arr[threadIndex] = Task.Factory.StartNew(PrintNum, threadIndex);
            }
            Task.WaitAll(arr);
            stopwatch.Stop();
            Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
            Console.Read();
        }


        private static void PrintNum(object num)
        {
            bool isOk = false;
            while (!isOk)
            {
                lock (cursorLock)
                {
                    int index = count % 2;
                    if (count>100)
                    {
                        isOk = true;
                    }
                    else if (index == (int)num)
                    {
                        if (index == 0) Console.WriteLine("{0}:{1} {2} ", "偶数线程", Thread.CurrentThread.ManagedThreadId, count++);
                        else Console.WriteLine("{0}:{1} {2} ", "奇数线程", Thread.CurrentThread.ManagedThreadId, count++);
                    }
                }
            }
        }

结果如下:

第四种方法 Mutex

        private static int i = 0;
        static Mutex mutex = new Mutex();
     
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            //ThreadStart是个委托
            Thread thread1 = new Thread(new ParameterizedThreadStart(show));
            thread1.Name = "偶数线程";
            Thread thread2 = new Thread(new ParameterizedThreadStart(show));
            thread2.Name = "奇数线程";
            thread1.Start(0);
            thread2.Start(1);
            thread2.Join();
            stopwatch.Stop();
            Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
            Console.Read();
        }
        /// <summary>
        /// Mutex的释放与锁定 都只能在同一个线程中执行
        /// </summary>
        private static void show(object index)
        {
            while (i <= 100)
            {
                mutex.WaitOne();
                int num = i % 2;
                if (num == (int)index&&i<=100)
                {
                    Console.WriteLine("{0}:{1}  {2}  ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId);
                }
                mutex.ReleaseMutex();
            }
           
        }

有关概念资料

https://www.jb51.net/article/180789.htm

到此这篇关于C#中AutoResetEvent控制线程用法小结的文章就介绍到这了,更多相关AutoResetEvent控制线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯