C#中的同步异步

根据项目中用到的做个总结

1.0 Mutex

概述:用于内部进程的“原始”同步。

跳过sample看后面的备注:2个或以上线程需要同时获取一个共享资源时,该类可以保证一个时间只有一个线程占用获取该资源。注意 exclusive的修饰,表明了具有排他性访问的能力。

问题1,多个线程运行是否有超时处理机制?

可以。WaitTimeout来指定等待时间。

问题2,能否用于一台机器的多个进程之间?

可以。通过Mutex的名字来实现多个进程之间,使用同一个Mutex,实现互斥访问资源。同时也支持 OpenExisting的方式打开现有的Mutex.

Mutex Class (System.Threading) | Microsoft Learn

samples

APP1和app2 是相同的代码,TEST1为互斥对象名字,每隔2秒模拟一次访问共享资源,

        Mutex _mutex = new Mutex(false, "TEST1");// 不同进程间使用同一个名字
        delegate void HandleLogMsg(string msg);
        HandleLogMsg _handleLogMsg;
        public MainWindow()
        {
            InitializeComponent();
            _handleLogMsg = Updatetext;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(() => {
                ThreadProc();
            });
        }
        private void ThreadProc()
        {
            while (true)
            {
                _mutex.WaitOne();
                var msg = $"App2: {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff}{Environment.NewLine}";
                this.Dispatcher.Invoke(_handleLogMsg, msg);
                Thread.Sleep(2000);
                _mutex.ReleaseMutex();
            }
        }
        private void Updatetext(string msg)
        {
            _tbMultiline.Text += msg;
            _tbMultiline.ScrollToEnd();
        }

  

2秒内只能有一个访问共享资源,通过此处的时间可知App1有时可以连续获得共享访问资源的资格,

 

 2.0 EventWaitHandle

EventWaitHandle Class (System.Threading) | Microsoft Learn

直接看Remarks的说明, 该类允许多个线程彼此通过信号来通信。典型地比如,一个或多个线程会被阻塞,直到一个非阻塞的线程设置了“绿灯” 即调用了Set 方法,绿灯后,一个或多个被阻塞的线程被释放去执行逻辑。

同上,与AutoResetEvent 和 ManualResetEvent相比,可以适用于不通进程间的同步。

为了解决保证上面2个进程交替访问共享资源,测试代码如下

APP1和2分别添加代码:

EventWaitHandle _ewh2 = new EventWaitHandle(false, EventResetMode.AutoReset, "TEST2");
EventWaitHandle _ewh3 = new EventWaitHandle(false, EventResetMode.AutoReset, "TEST3");
//APP2添加 
private void ThreadProc2() { while (true) { _ewh2.WaitOne(); var msg = $"App2: {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff}{Environment.NewLine}"; this.Dispatcher.Invoke(_handleLogMsg, msg); Thread.Sleep(2000); _ewh3.Set(); } }
//APP1添加
 private void ThreadProc2()
        {
            _ewh2.Set();//允许APP2先执行,从而触发交替访问
            while (true)
            {
                _ewh3.WaitOne();
                var msg = $"App1: {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff}{Environment.NewLine}";
                this.Dispatcher.Invoke(_handleLogMsg, msg);
                Thread.Sleep(2000);
                //EventWaitHandle.SignalAndWait(_ewh2, _ewh3);
                _ewh2.Set();
            }
        }

测试结果:App2先执行,符合预期;App2和app1,时间间隔都在4秒,说明交替执行。

备注:二者均在74行,时间间隔为4.008、4.009秒,为误差秒,

 3.0 信号用于控制线程的 暂停 和 继续

增加如下代码到项目App1,

 ManualResetEvent _ewh3_1 = new ManualResetEvent(true);
 CancellationToken _token;
 CancellationTokenSource _tokenSource = new CancellationTokenSource();
 private void ThreadProc3()
        {
            while (true)
            {
                if (_token.IsCancellationRequested)
                    return;

                _ewh3_1.WaitOne();
                var msg = $"App1: {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff}{Environment.NewLine}";
                this.Dispatcher.Invoke(_handleLogMsg, msg);
                Thread.Sleep(2000);
            }
        }
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            _ewh3_1.Reset();
        }
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            _ewh3_1.Set();
        }

ManualResetEvent(true),true 表明初始信号为允许执行,会影响waitone的行为为。

FALSE:所有调用了WaitOne的线程将进入阻塞状态,直到某些线程调用了Set方法;

TRUE:所有调用了WaitOne的线程将不进入阻塞状态,自由执行WaitOne后的逻辑;

测试结果:持续以每2秒输出,点击暂停后停止动作,点击继续后继续输出。

 

 

  

 

  

  

  

posted on 2022-11-16 07:56  益而不损  阅读(390)  评论(0)    收藏  举报