首页 > 编程语言 >C# .netframework 4.5 下的 lock 语法 已经够用了,挺安全的。

C# .netframework 4.5 下的 lock 语法 已经够用了,挺安全的。

时间:2025-01-11 09:01:59浏览次数:1  
标签:4.5 BEGIN netframework END Thread C# add WriteLine Debug

如果你在一个线程里用 lock语法  锁住了某段数据,当外部粗暴的 abort 或 interrupt 这个线程后,退出线程前,这个 lock 会自动释放了。

我做了一个简单的例子来模拟情况,先是写了一个 类 Class2,里面有一个 int _count 用来在线程间互斥的修改,用一个 _locker 来保护。

提供了四个方法:

start(),创建线程并运行。运行起来,先会用 lock(_locker) 加锁保护,在保护内 _count 加1,然后,就sleep这个线程1小时。1小时到期后,会退出锁保护。

abort(),interrupt(),都会触发上面那个线程中断。

 add(),先会用 lock(_locker) 加锁保护,在保护内 _count 加1,再退出锁保护。

 

然后创建一个FORM,在这个FORM 上有四个按键,一个是创建线程并运行(start thread),另一个是 abort 这个线程,还有一个是 interrupt 这个线程,最后一个是 add 一个值。注意因为 add 时会被锁住,所以,add 这里又创建一个线程去 调用 上面那个类里的 add,这样,界面上的 add 就可以反复按而不住卡住 FORM 主线程。

这是那个 Class2.cs。

using System;
using System.Threading;
using System.Diagnostics;

namespace testThreadForm
{
    public class Class2
    {
        private object _locker = new object();
        private Thread _t = null;
        private int _count = 0;

        public void Start()
        {
            Debug.WriteLine("[{0}] Start: BEGIN.", Thread.CurrentThread.ManagedThreadId);
            if (null != _t)
            {
                _t.Abort();
                _t.Join();
                _t = null;
            }

            _t = new Thread(new ThreadStart(_backgroundLoop));
            _t.Start();
            Debug.WriteLine("[{0}] Start: END.", Thread.CurrentThread.ManagedThreadId);
        }

        public void Interrupt()
        {
            Debug.WriteLine("[{0}] Interrupt: BEGIN.", Thread.CurrentThread.ManagedThreadId);
            if (null != _t)
            {
                _t.Interrupt();
            }
            Debug.WriteLine("[{0}] Interrupt: END.", Thread.CurrentThread.ManagedThreadId);
        }

        public void Abort()
        {
            Debug.WriteLine("[{0}] Abort: BEGIN.", Thread.CurrentThread.ManagedThreadId);
            if (null != _t)
            {
                _t.Abort();
            }
            Debug.WriteLine("[{0}] Abort: END.", Thread.CurrentThread.ManagedThreadId);
        }

        public void Add()
        {
            Debug.WriteLine("[{0}] Add: BEGIN.", Thread.CurrentThread.ManagedThreadId);
            lock (_locker)
            {
                ++_count;
                Debug.WriteLine("[{1}] ADD: count = {0}", _count, Thread.CurrentThread.ManagedThreadId);
            }
            Debug.WriteLine("[{0}] Add: END.", Thread.CurrentThread.ManagedThreadId);
        }

        private void _backgroundLoop()
        {
            Debug.WriteLine("[{0}] Loop: BEGIN.", Thread.CurrentThread.ManagedThreadId);
            try
            {
                lock (_locker)
                {
                    _count++;
                    Thread.Sleep(1000 * 60 * 60);
                }
            }
            catch (ThreadInterruptedException)
            {
                Debug.WriteLine("[{0}] Loop: ThreadInterruptedException awoken.",
                          Thread.CurrentThread.ManagedThreadId);
            }
            catch (ThreadAbortException)
            {
                Debug.WriteLine("[{0}] Loop: ThreadAbortException aborted.",
                                  Thread.CurrentThread.ManagedThreadId);
            }
            finally
            {
                Debug.WriteLine("[{0}] Loop: END.", Thread.CurrentThread.ManagedThreadId);
            }
        }
    }
}

这是 主 FORM 里的调用。

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace testThreadForm
{
    public partial class Form1 : Form
    {
        Class2 c = new Class2();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            c.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            c.Abort();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(_add));
            t.Start();
        }

        private void _add()
        {
            Debug.WriteLine("[{0}] _add: BEGIN", Thread.CurrentThread.ManagedThreadId);
            c.Add();
            Debug.WriteLine("[{0}] _add: END", Thread.CurrentThread.ManagedThreadId);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            c.Interrupt();
        }
    }
}

这是按如下操作后的结果:

1)按下 start thread

2)按下 add 

3)按下 abort

4)按下 start thread

5)按下 add

6)按下 interrupt

[1] Start: BEGIN.
[1] Start: END.
[3] Loop: BEGIN.
[4] _add: BEGIN
[4] Add: BEGIN.
[1] Abort: BEGIN.
Exception thrown: 'System.Threading.ThreadAbortException' in mscorlib.dll
[4] ADD: count = 2
[3] Loop: ThreadAbortException aborted.
Exception thrown: 'System.Threading.ThreadAbortException' in testThreadForm.exe
[4] Add: END.
[3] Loop: END.
[1] Abort: END.
The thread 0x6578 has exited with code 0 (0x0).
[4] _add: END
The thread 0x2508 has exited with code 0 (0x0).

[1] Start: BEGIN.
[1] Start: END.
[5] Loop: BEGIN.
[6] _add: BEGIN
[6] Add: BEGIN.
[1] Interrupt: BEGIN.
[1] Interrupt: END.
Exception thrown: 'System.Threading.ThreadInterruptedException' in mscorlib.dll
[5] Loop: ThreadInterruptedException awoken.
[6] ADD: count = 4
[6] Add: END.
[6] _add: END
The thread 0x5fc has exited with code 0 (0x0).
[5] Loop: END.
The thread 0x4994 has exited with code 0 (0x0).

 

标签:4.5,BEGIN,netframework,END,Thread,C#,add,WriteLine,Debug
From: https://www.cnblogs.com/pencilstart/p/18665137

相关文章

  • 【华为OD技术面试手撕真题】- C++手撕技术面试八股文(1)
    文章目录一、delete和delete[]的区别二、const解释一下其作用1.定义常量2.修饰指针3.修饰函数参数4.修饰类成员函数三、struct和class的区别1.默认访问控制2.继承的默认访问控制四、#include<file.h>#include"file.h"的区别五、C++文件......
  • JavaScript 高阶技巧
    文章目录1、解构赋值的别名2、Currying3、防抖与节流4、记忆化5、代理对象6、生成器7、善用控制台8、结构化克隆9、自执行函数10、标记模版字符串1、解构赋值的别名解构赋值允许你从数组或对象的属性中提取值并将其分配给不同的变量。别名允许你在这一过程中重命名......
  • Discharging Method
    Firstly,weintroduceEulerFormula.WhenweuseEulerformula,weoftenneeditstransformations.Secondly,wedesignsomedischargingrulesbasedonEulerFormula.Finally,wegivetheprincipleofDischargingMethodinproofs.......
  • ubuntu20.04部署k8s集群(基于docker)
    Ubuntu部署k8s集群(基于docker)本文总结一下部署k8s集群踩的坑以及部署流程。相关版本:docker-v27.4.1、cri-dockerd-v0.3.16、kubeadm-v1.28.15注意本人的机器是arm64的,x86已经amd64的可以参考目前仅完成至基础配置阶段(到集群初始化)k8s介绍Kubernetes是一个开源的容器编排......
  • Scala语言的软件开发工具
    Scala语言的软件开发工具Scala是一种静态类型的编程语言,它结合了面向对象和函数式编程的特性。自2003年由马丁·奥德斯基(MartinOdersky)发明以来,Scala因其简洁的语法和强大的功能,逐渐成为了现代软件开发领域的重要语言之一。为了更高效地使用Scala进行软件开发,许多工具和框......
  • Clojure语言的学习路线
    Clojure语言的学习路线Clojure是一种现代的Lisp方言,运行于Java虚拟机(JVM)上。它具备强大的函数式编程特性,支持并发和多线程编程,适合处理复杂的数据和计算任务。由于其简洁和灵活的语法,Clojure在数据科学、后端开发以及Web开发等领域得到了广泛的应用。为了帮助初学者顺利入......
  • python SQLAlchemy ORM——从零开始学习 04 如何过滤(筛选)数据库中的数据
    04如何过滤(筛选)数据库中的数据从数据库中获筛选数据主要应用以下几个接口:filter、filter_by、以及where。前两个在02已经展开说过,先展开说where接口前情提要:依赖03提及的model【本质上就是数据库的链接,有可忽视】当前的数据库表内容如下,仅作例子,不相同根据自身数据库操作即......
  • C++语言的学习路线
    C++语言的学习路线C++是一种强大的高级编程语言,广泛应用于系统软件、游戏开发、嵌入式系统和高性能应用等多个领域。由于其丰富的功能和灵活性,C++是一门值得深入学习的语言。本文旨在为初学者制定一条系统的学习路线,帮助他们循序渐进地掌握C++语言。第一阶段:基础知识1.......
  • 用eNSP实现DHCP与全网通
    目录一、基本概念(一)DHCP(二)全网通二、eNSP的命令解析(一)DHCP(二)全网通三、问题实现1.先将给到的192.168.1.0/24网段通过子网划分,分为四个网段。2.配置三个路由器的ip3.实现DHCP分配地址4.实现全网通一、基本概念路由器的工作原理:当消息进行发送时,PC端会首先根据目......
  • pytorch模型的保存失敗しましたが、
    目录简洁: 评估模式后缀区别保存模型(整个模型)加载过程:保存状态字典加载过程:总结把模型训练到一半保存,想下次接着训练,用那种保存方式保存模型和优化器状态字典加载模型和优化器状态字典如果保存整个模型,就不能继续训练吗、保存整个模型加载整个模型并继续训练......