Form1单例模式与互斥锁
一、使用mutex来解决。
如何让窗体Form1也是一个单例模式呢?
在窗体项目中找到Program.cs,双击。找到入口点,更改如下:
[STAThread]private static void Main(){string mutexName = "MyapplicatonMutexApp1121";using (Mutex m = new Mutex(true, mutexName, out bool isFist)){if (isFist == false){MessageBox.Show("已经在运行了.");return;}Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}}
上述代码是一个C#控制台应用程序的入口方法Main,它使用了STAThread属性和互斥锁来
控制应用程序的运行。
首先,定义了一个字符串变量mutexName来表示互斥锁的名称。互斥锁是一种同步机制,
用于在多个线程之间实现资源的互斥访问,确保同一时间只有一个线程可以访问被保护的资
源。
接下来,使用using语句以编程方式创建一个互斥锁Mutex。Mutex构造函数的第一个参数
为true,表示创建一个初始状态为"有信号"的互斥锁。第二个参数是互斥锁的名称,用于唯一
标识这个互斥锁。第三个参数out bool isFirst是一个out参数,用于返回一个布尔值,指示
是否是第一个线程获得了互斥锁。
接下来,通过检查isFirst的值来判断是否是第一个获得互斥锁的线程。如果isFirst的
值为false,则说明已经有另一个实例正在运行,弹出一个消息框提示用户已经在运行,并
直接退出应用程序;如果isFirst的值为true,则说明当前是第一个获得互斥锁的线程,继
续执行应用程序。
当应用程序第一次运行时,它将获得互斥锁,然后调用Application.EnableVisualStyles()和
Application.SetCompatibleTextRenderingDefault(false)方法来启用可视化样式和设置文
本呈现默认值。最后,调用Application.Run(new Form1())运行主窗体Form1,启动应用程序
的消息循环,处理用户界面和事件。
因此,上面保证只有一个实例运行,通过互斥锁来控制应用程序的运行。当多个实例尝
试运行时,只有第一个实例能够成功获得互斥锁并继续执行,其他实例将被提示已经在运行,
并退出应用程序。这种方法通常用于单实例应用程序,以确保不会同时启动多个相同的应用
程序实例。
问:上面[STAThread]有什么用?
答:[STAThread]是一个属性,用于指定应用程序的线程模型。上面应用于Main方法,用于确
保应用程序在单线程单元(STA)模式下执行。
在多线程应用程序中,STA模式是一种线程模型,它要求应用程序的所有线程都在单个单
元中执行,并且每个线程都与消息循环相关联。这对于许多GUI框架和组件是必需的,因为它
们通常依赖于在单个线程中进行消息处理。
[STAThread]属性告诉应用程序使用STA模式运行。该属性可以应用于整个应用程序(在
入口点Main方法上)或特定线程。确保应用程序以STA模式运行对于使用Windows Forms、WPF
或COM组件的应用程序是必要的。
如果应用程序需要与其他线程进行互操作,可能需要考虑使用不同的线程模型,如多线
程单元(MTA)模式。但在大多数情况下,使用[STAThread]来运行应用程序是常见和推荐的做
法。
STA(单线程单元)模式可以实现按顺序执行,减少多线程竞争资源的问题,并且能够
提供一致和可预测的程序执行顺序。但在某些情况下,例如需要处理大量计算密集型任务或
需要与其他线程进行并行操作的场景,MTA(多线程单元)模式可能更适合。在这种情况下,
需要仔细考虑线程同步和资源竞争问题,并采取适当的并发控制措施。
问:Mutex m = new Mutex(true, mutexName, out bool isFist)是什么意思?
答:此句用Mutex 类来创建一个互斥锁,并指定了参数。m 是一个 Mutex 类型的变量,用于
表示创建的互斥锁。
new Mutex(true, mutexName, out bool isFist) 是创建 Mutex 实例的构造函数调用:
true 表示在创建互斥锁时设置一个初始状态,即锁定状态。(上锁)
mutexName 是一个字符串参数,用于指定互斥锁的名称。
out bool isFist 是一个输出参数,用于指示是否是第一次创建互斥锁。
因此,这段代码的功能是创建一个名为 mutexName 的互斥锁,并在创建时将其锁定。
同时,通过 out bool isFist 参数返回一个布尔值,指示是否是第一次创建该互斥锁。
第一个参数 true 表示在创建互斥锁时将其初始化为锁定状态。这意味着在调用
new Mutex(true, mutexName, out bool isFist) 时,如果其他线程已经锁定了该互斥
锁,则创建过程将会失败,isFist 参数将会被设置为 false。
如果创建成功,则 isFist 参数将会被设置为 true,表示当前线程是第一个锁定
该互斥锁的线程。
如果第一个参数为 false,则无论其他线程是否已经锁定了该互斥锁,isFist 参数
都会被设置为 false。
通俗解释:mutex的Name属性很重要,它是识别mutex锁的重要标志。可以命名不同的锁,尽量长而具有唯一识别性,第二次来判断这个mutex锁就是根据这个Name。当然你也可以用唯一GUID来识别,但第二次运行时会重新生成另一个GUID,肯定与第一次的不同,除非,你把GUID保存在硬盘日志上,下次运行时,先读取硬盘从而取出GUID。为了简省,采取较长且多样字符的来命名Name,省去读日志文件的麻烦。
m = new Mutex(true, mutexName, out bool isFist)这一句就是上锁,设置初始拥有true,因此,如果上锁成功isFirst为true,说明之前没有实例进行上锁,没有人拥有这个锁。这个时候就可以运行实例。但如果现在上锁失败,说明已经被别人拥有,别人已经锁上了,自己进不了,也就是已经有实例在运行了,所以第二次运行只有退出,从而保证只有一实例。
二、理解Mutex
1、当我们想要确保多个线程同时访问某个共享资源时不会产生冲突时,可以使用Mutex类。
你可以把Mutex类看作是一个特殊的锁,它可以帮助我们控制对共享资源的访问。
你可以将Mutex类比作一间只能容纳一人的厕所。每当一个人想要使用厕所时,他必
须先查看门口的指示灯。如果指示灯是红色的,意味着有人正在使用厕所,那么他就需
要等待。如果指示灯是绿色的,意味着厕所是空闲的,他就可以进去并将指示灯设置为
红色,这样其他人就必须等待。
在代码中,我们创建了一个Mutex对象来代表这个厕所。当一个线程想要访问共享资
源时,它需要调用Mutex对象的WaitOne()方法来查看指示灯状态。如果指示灯是红色的
(即Mutex被锁定),线程就会被阻塞等待。当指示灯是绿色的时候,线程可以继续执行,
并调用Mutex对象的ReleaseMutex()方法将指示灯设置为红色,这样其他线程就必须等待。
使用Mutex类可以确保共享资源在同一时间只能由一个线程访问,从而避免了数据竞争和
冲突。它是一种有力的工具,用于实现多线程代码的同步和互斥操作。
2、Mutex类
Mutex类提供了对互斥锁进行操作和管理。常用的属性与方法:
Name属性:获取或设置Mutex对象的名称。
Mutex myMutex = new Mutex(false, "MyMutex");// 创建一个具有指定名称的Mutex对象string mutexName = myMutex.Name;// 获取Mutex对象的名称
SafeWaitHandle属性:获取一个安全句柄,用于操作底层操作系统的同步原语。
Mutex myMutex = new Mutex();// 创建一个Mutex对象SafeWaitHandle safeHandle = myMutex.SafeWaitHandle;// 获取SafeWaitHandle属性
Mutex() 构造函数:创建一个Mutex对象。
Mutex myMutex = new Mutex();// 创建一个Mutex对象,默认为非继承的互斥对象Mutex myInheritedMutex = new Mutex(true, "MyMutex", out bool createdNew);// 创建一个继承的互斥对象
WaitOne() 方法:阻塞当前线程,直到Mutex对象变为可用。
Mutex myMutex = new Mutex();// 创建一个Mutex对象myMutex.WaitOne();// 等待Mutex对象变为可用...// 执行需要互斥访问的代码myMutex.ReleaseMutex();// 释放Mutex对象
WaitOne(TimeSpan timeout) 方法:阻塞当前线程,直到Mutex对象变为可用,或者等待超时。
Mutex myMutex = new Mutex();// 创建一个Mutex对象TimeSpan timeout = TimeSpan.FromSeconds(2);// 设置等待超时时间为2秒bool mutexAcquired = myMutex.WaitOne(timeout);// 等待Mutex对象变为可用,或者等待超时if (mutexAcquired){...// 执行需要互斥访问的代码myMutex.ReleaseMutex();// 释放Mutex对象}else{...// 等待超时,执行其他操作}
ReleaseMutex() 方法:释放Mutex对象,使其可供其他线程访问。
Mutex myMutex = new Mutex();// 创建一个Mutex对象myMutex.WaitOne();// 等待Mutex对象变为可用...// 执行需要互斥访问的代码myMutex.ReleaseMutex();// 释放Mutex对象
Close() 方法:释放并关闭Mutex对象。
Mutex mutex = new Mutex();// 创建一个Mutex对象...// 执行一些操作mutex.Close();// 释放并关闭Mutex对象
问:Mutex只能在一个线程中吗?
答:不,Mutex在C#中并不限制只能在一个线程中使用。Mutex是一种系统级别的同步原
语,可以用于跨线程、跨进程的互斥操作。
在同一个进程中的多个线程可以使用同一个Mutex对象来实现互斥访问共享资源的目
的。当一个线程获取到Mutex的锁时,其他线程将会被阻塞等待,直到锁被释放。这样可
以确保同一个进程中的多个线程不会同时访问共享资源,避免出现冲突。
此外,Mutex还可以用于跨进程的互斥操作。在不同的进程中,可以通过使用具有相
同名称的Mutex对象来进行互斥操作。这样,不同进程中的线程就可以通过Mutex来同步
对共享资源的访问。
总结:Mutex既可以用于同一个线程内部的互斥操作,也可以用于不同线程、不同进
程之间的互斥操作,以实现并发控制和资源保护。
问:mutex中的Close与ReleaseMutex有什么区别?
答:Close()方法用于释放Mutex对象占用的资源。当你不再需要使用Mutex对象时,可以
调用Close()方法来显式地释放资源,以便后续的垃圾回收器可以回收相应资源。调用
Close()方法后,你将无法再使用该Mutex对象。
ReleaseMutex()方法用于释放Mutex对象的锁。当你在某个线程中调用WaitOne()方
法获取了Mutex的锁之后,你可以在适当的时候调用ReleaseMutex()方法来释放该锁,以
允许其他等待线程获得该锁并继续执行。每次调用WaitOne()方法成功后,需要对应调用
ReleaseMutex()方法来释放锁。
简言之:Close()方法用于释放对象;而ReleaseMutex()方法用于释放锁,对象仍在。
问:WaitOne()与WaitOne(TimeSpan)的区别?
答:两者都用于等待获取Mutex互斥锁。
WaitOne():没有参数,它会一直等待直到获取到Mutex或超时。如果Mutex当前不可
用,调用WaitOne()的线程将被阻塞,直到Mutex可用或者被中断。如果获取到Mutex,
WaitOne()会返回true。如果等待过程中发生了异常或调用被中断,WaitOne()会返回
false。
WaitOne(TimeSpan):接受一个TimeSpan类型的参数,用于指定最大等待时间。如果
Mutex在指定的时间内可用,该方法会获取到Mutex并返回true。如果Mutex在指定的时间
内不可用,该方法会返回false,表示超时。如果等待过程中发生了异常或调用被中断,
WaitOne(TimeSpan)会返回false。
WaitOne()没有超时设置,会一直阻塞等待;而WaitOne(TimeSpan)允许设置最大等
待时间,在超过该时间后会返回超时结果。WaitOne(0)立即返回结果。
3、上面的Mutex在取互拆锁时,可能超时,怎么修正单例模式?
[STAThread]private static void Main(){string mutexName = "MyapplicatonMutexApp1121";using (Mutex m = new Mutex(true, mutexName, out bool isFist)){if (isFist == false){MessageBox.Show("已经在运行了.");return;}bool acquiredLock = m.WaitOne(TimeSpan.FromSeconds(1));//等待1秒后尝试获取互斥锁if (!acquiredLock)//失败{MessageBox.Show("获取互斥锁超时。");return;//超时也认为在运行,所以需要人为再运行看提示。}Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}}
问:为什么会有延迟?
答:获取互斥锁时,可能会出现延迟的情况有多种原因,导致已经释放,但获取失败。
比如:线程调度、系统资源竞争、阻塞操作、垃圾回收等等,原因通常是在多线程
环境下或与外部资源的交互中比较常见的。虽然我们不能完全消除延迟,但可以采取一
些措施来最小化延迟的影响,例如使用合理的线程调度策略、避免过度竞争共享资源、
进行异步操作以减少阻塞等。
三、应用举例
一个常见的使用Mutex的经典例子是多个线程同时读写共享的全局变量。在这个例子中,
我们使用Mutex来确保同一时间只有一个线程能够访问共享变量。
class Program{static int sharedVariable = 0;static Mutex mutex = new Mutex();static void Main(string[] args){for (int i = 0; i < 5; i++)// 创建并启动多个线程{Thread t = new Thread(IncrementSharedVariable);t.Start();}Thread.Sleep(2000);// 等待所有线程执行完成Console.WriteLine("Shared Variable: " + sharedVariable);// 输出最终的共享变量的值Console.ReadLine();}static void IncrementSharedVariable(){mutex.WaitOne();// 等待获取Mutex的锁sharedVariable++;// 对共享变量进行操作mutex.ReleaseMutex();// 释放Mutex的锁}}
在上面的例子中,有多个线程同时执行IncrementSharedVariable方法来对
sharedVariable进行自增操作。由于使用了Mutex,每次只有一个线程能够获取到Mutex的锁,
执行自增操作并释放锁。
通过使用Mutex,我们确保了对sharedVariable的访问是互斥的,避免了多个线程同时
对其进行写操作导致的数据竞争和不确定行为。最终,我们可以正确地得到共享变量的最终
值。
上面因为执行很快,所以直接用了等待2秒。下面用程序来判断线程都结束.
internal class Program{private static int shareVariable = 0;private static Mutex mutex = new Mutex();private static void Main(string[] args){Thread[] threads = new Thread[5];for (int i = 0; i < 5; i++){threads[i] = new Thread(IncrementSharedVariable);threads[i].Start();}foreach (Thread thread in threads){thread.Join();}Console.WriteLine(shareVariable);Console.ReadKey();}private static void IncrementSharedVariable(){mutex.WaitOne();shareVariable++;mutex.ReleaseMutex();}}
thread.Join()是什么意思?
当主线程开始运行时,会迅速创建并启动5个线程。然后,在主线程中使用foreach循环
遍历所有线程,并在每个线程上调用Join()方法,这会阻塞主线程,直到相应的线程执行完
成。
主线程会周期性地检查每个线程的状态,直到所有线程都执行完成。一旦所有线程执行
完成,Join()方法会立即返回,主线程不再被阻塞,接下来的代码会继续执行。
这种方式保证了主线程在输出最终的共享变量之前等待所有线程执行完成。它是一种有
效的方式来确保所有线程完成后再继续程序的执行。
简言之,主程序暂停,直到Join()里所有线程完成,主线程继续向下执行。
相关文章:
Form1单例模式与互斥锁
一、使用mutex来解决。 如何让窗体Form1也是一个单例模式呢? 在窗体项目中找到Program.cs,双击。找到入口点,更改如下: [STAThread]private static void Main(){string mutexName "MyapplicatonMutexApp1121";usin…...

MySQL | 常用命令示例
MySQL | 常用命令示例 一、启停MySQL数据库服务二、连接MySQL数据库三、创建和管理数据库四、创建和管理数据表五、数据备份和恢复六、查询与优化 MySQL是一款常用的关系型数据库管理系统,广泛应用于各个领域。在使用MySQL时,我们经常需要编写一些常用脚…...

常见网关对比
常见网关对比 目前常见的开源网关大致上按照语言分类有如下几类: Nginxlua :OpenResty、Kong、Orange、Abtesting gateway 等 Java :Zuul/Zuul2、Spring Cloud Gateway、Kaazing KWG、gravitee、Dromara soul 等 Go :Janus、fa…...
机器学习动量优化算法笔记
动量优化算法(Momentum Optimization)是一种常用于训练神经网络的优化算法。它通过模拟物体在惯性作用下的运动来加速梯度下降过程,从而加快神经网络的收敛速度并提高训练效率。 在梯度下降算法中,每次更新权重时都是根据当前批次…...
asp.net与asp.net优缺点及示例
Asp.net Mvc架构模式是一种低耦合、可测试的web应用程序框架,它是基于CLR和成熟的MVC架构构建的。ASP .NET MVC不支持 ViewState和服务器控件。 Asp.net优点: 1.架构降低了程序间的耦合性,M VC,分层,目标明确 2.性能不支持viewsta…...
php 年月日 分组分页
//年月日 //分组 分页$type $this->request->type;$dateType "%Y-%m";//月$dateType1 "CONCAT(tmp.date,-01 00:00:00)";$dateType2 "CONCAT(LAST_DAY(CONCAT(tmp.date, -15)), 23:59:59)";if ($type day) {//日$dateType "%Y-…...
flutter开发实战-请求dio设置Cookie
flutter开发实战-请求dio设置Cookie 在最近开发中碰到了需要websocket长链接收到响应的auth,在之后的请求中需要将其设置为cookie中。 如Cookie:authDHSfQQSAXf89xZqJTLdEDVI2hwzc7p2lUmSNNdUSlgW2MyfQINpYr7jUbkX/; 设置cookie用到了dio_cookie_manager组件 一、…...

C语言第十一课--------操作符的使用与分类-------基本操作
作者前言 作者介绍: 作者id:老秦包你会, 简单介绍: 喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 个人主页::小小页面 gitee页面:秦大大 一个爱分享的小博主 欢迎小可爱们…...

2,继承、内联函数、虚继承、友元、构造析构函数、初始化列表
继承 2.1结构体成员权限2.1.1访问权限2.1.2类与结构体 2.2类的成员函数2.2.1类内规则2.2.2类成员内联函数inline 2.3类的继承2.3.1类的继承与成员函数2.3.2类的多继承2.3.2.1类的多继承:菱形问题提出 2.3.3类的虚继承(关键字virtual) 2.4友元…...

Mkdocs中利用Js实现大小圈鼠标拖动样式
在docs/javascripts/extra.js下复制粘贴: var CURSOR;Math.lerp (a, b, n) > (1 - n) * a n * b;const getStyle (el, attr) > {try {return window.getComputedStyle? window.getComputedStyle(el)[attr]: el.currentStyle[attr];} catch (e) {}return …...

pytorch(6)——神经网络基本骨架nn.module的使用
1 神经网络框架 1.1 Module类的使用 NN (Neural network): 神经网络 Containers: 容器 Convolution Layers: 卷积层 Pooling layers: 池化层 Padding Layers: 填充层 Non-linear Activations (weighted sum, nonlinearity): 非线性激活 Non-linear Activations (other): 非线…...

论文精读之BERT
目录 1.摘要(Abstract) 2.引言(Introduction): 3.结论(Conlusion): 4.BERT模型算法: 5.总结 1.摘要(Abstract) 与别的文章的区别是什么:BERT是用来设计去…...

实战:Docker+Jenkins+Gitee构建CICD流水线
文章目录 前言Jenkins部署创建Jenkins docker-compose配置maven源启动Jenkins容器安装插件Gitee ssh公匙配置与测试项目提交 Jenkins创建流水线写在最后 前言 持续集成和持续交付一直是当下流行的开发运维方式,CICD省去了大量的运维时间,也能够提高开发…...

7.25 Qt
制作一个登陆界面 login.pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on …...
P1420 最长连号
题目描述 输入长度为 n n n 的一个正整数序列,要求输出序列中最长连号的长度。 连号指在序列中,从小到大的连续自然数。 输入格式 第一行,一个整数 n n n。 第二行, n n n 个整数 a i a_i ai,之间用空格隔开…...
UVA-1354 天平难题 题解答案代码 算法竞赛入门经典第二版
GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 这道题需要: 1. 遍历二叉树的每种构成方式。我这里每次把当前所有结点列出,然后遍历选取两个组合构成一个新结点,原来的结点剔除,新结点加入。…...

电机故障诊断(python程序,模型为CNN结合LSTM)
代码运行环境要求:TensorFlow版本>2.4.0,python版本>3.6.0 运行效果视频:电机故障诊断(python代码)_哔哩哔哩_bilibili 1.电机常见的故障类型有以下几种: 轴承故障:轴承是电机运转时最容…...

ubuntu 20.04 rtc时间显示问题探究
1、硬件与软件 本次测试的硬件为RK3568芯片,操作系统为ubuntu 20.04。 2、RTC与系统时间 先说结果,如果RTC驱动不可用或者RTC内部存储的时间非法, 那么操作系统会存储上一次有效的时间,当再次上电时,date命令会使用存储…...

数值分析第七章节 用Python实现非线性方程与方程组的数值解法
参考书籍:数值分析 第五版 李庆杨 王能超 易大义编 第7章 非线性方程与方程组的数值解法 文章声明:如有发现错误,欢迎批评指正 文章目录 迭代法求解 x e x − 1 0 xe^x-10 xex−10牛顿法求解 x e x − 1 0 xe^x-10 xex−10简化牛顿法求解 …...

利用MATLAB制作DEM山体阴影
在地理绘图中,我们使用的DEM数据添加山体阴影使得绘制的图件显得更加的美观。 GIS中使用ArcGIS软件就可以达到这一目的,或者使用GMT,同样可以得到山体阴影的效果。 本文提供了一个MATLAB的函数,可以得到山体阴影。 clear all;c…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...