当前位置: 首页 > news >正文

[C#] 多线程单例子,分为阻塞型和分阻塞型, 在unity里的应用

在单例中使用多线程时,需要注意以下几点:

  • 线程安全:在多线程环境下,单例对象可能被多个线程同时访问,因此需要确保单例的线程安全,避免出现数据竞争等问题。

  • 对象创建:如果在单例对象的构造函数中启动了新的线程,那么可能会在单例对象还没有完全创建完成时就开始执行线程。因此,在创建单例对象时需要考虑到线程的启动时机,可以使用懒汉式的延迟加载方式,在需要使用单例对象时再进行初始化。

  • 生命周期管理:如果在单例对象中启动了线程,那么需要考虑线程的生命周期管理,避免线程一直运行导致资源泄漏等问题。可以在单例对象的析构函数中停止线程,或者提供额外的接口供外部调用停止线程。

以下是一个在单例中使用多线程的示例代码:


public class Singleton
{private static Singleton instance = null;private static readonly object padlock = new object();private Thread workerThread;private bool stopWorkerThread = false;public static Singleton Instance{get{lock (padlock){if (instance == null){instance = new Singleton();}return instance;}}}private Singleton(){workerThread = new Thread(WorkerThreadMethod);workerThread.Start();}private void WorkerThreadMethod(){while (!stopWorkerThread){// Do some work...}}public void StopWorkerThread(){stopWorkerThread = true;}~Singleton(){StopWorkerThread();}
}

在这个例子中,Singleton 是一个单例类,它在构造函数中启动了一个工作线程,并且提供了一个 StopWorkerThread 接口用于停止工作线程。在 Singleton 的析构函数中会调用 StopWorkerThread 接口来停止工作线程,确保线程的生命周期管理。在使用 Singleton 时,可以通过 Singleton.Instance 来获取单例对象,并且可以调用 StopWorkerThread 接口来停止工作线程。

非阻塞型

将GetInstance()的返回类型从Task改为UniTask,这是Unity针对异步编程所提供的更高效的API。
将_instance声明为UniTaskCompletionSource类型,并在Initialize()方法完成后使用TrySetResult()方法将结果赋值给_instance。
在Instance属性中使用AsyncLazy类型来实现延迟初始化,并确保多个线程安全地访问单例。
下面是修改后的代码示例:

using Cysharp.Threading.Tasks;public abstract class SingletonTask<T> where T : SingletonTask<T>, new()
{private static readonly AsyncLazy<T> _instance = new AsyncLazy<T>(async () =>{var instance = new T();await instance.InitializeAsync();return instance;});public static UniTask<T> InstanceAsync => _instance.Value;protected virtual UniTask InitializeAsync(){return UniTask.CompletedTask;}
}

这里我们使用了AsyncLazy来延迟初始化单例,并将Initialize()方法改为InitializeAsync(),返回UniTask类型。注意到InitializeAsync()方法是虚方法,方便子类进行实现。

使用时,可以通过调用InstanceAsync属性来获取单例,例如:


public class GameManager : SingletonTask<GameManager>
{private int _score = 0;public void AddScore(int score){_score += score;}protected override UniTask InitializeAsync(){Debug.Log("Game manager initialized.");return UniTask.CompletedTask;}
}// 在其他地方获取GameManager单例
GameManager.InstanceAsync.ContinueWith(gameManager => {gameManager.AddScore(100);
});

这里通过ContinueWith方法来在获取单例后执行添加分数的操作,而不需要等待单例初始化完成。

阻塞型

如果需要等待单例初始化完成,可以在获取单例的时候返回一个 Task 对象,并在单例初始化完成后 Task 对象得到通知。具体的实现可以参考下面的代码:


public abstract class SingletonTask<T> where T : SingletonTask<T>, new()
{private static readonly object padlock = new object();private static T _instance;private static TaskCompletionSource<T> _tcs;public static async Task<T> GetInstanceAsync(){if (_instance != null){return _instance;}if (_tcs == null){_tcs = new TaskCompletionSource<T>();}await _tcs.Task;return _instance;}protected SingletonTask(){lock (padlock){if (_instance != null){throw new InvalidOperationException("Cannot create multiple instances of singleton.");}_instance = this as T;_tcs?.TrySetResult(_instance);}}public abstract Task Initialize();
}

在上面的代码中,GetInstanceAsync 方法返回一个 Task 对象,如果单例已经初始化完成,则直接返回单例;否则创建一个 TaskCompletionSource 对象 _tcs 并返回其 Task 属性。当单例初始化完成时,调用 _tcs.TrySetResult(_instance) 方法,通知等待该 Task 的代码,单例已经初始化完成。具体使用方式如下:


public class MySingleton : SingletonTask<MySingleton>
{private MySingleton(){}public override async Task Initialize(){// 初始化代码await Task.Delay(1000);}
}// 获取单例,并等待初始化完成
var instance = await MySingleton.GetInstanceAsync();

上述代码会等待 MySingleton 的初始化完成,然后返回单例对象。

相关文章:

[C#] 多线程单例子,分为阻塞型和分阻塞型, 在unity里的应用

在单例中使用多线程时&#xff0c;需要注意以下几点&#xff1a; 线程安全&#xff1a;在多线程环境下&#xff0c;单例对象可能被多个线程同时访问&#xff0c;因此需要确保单例的线程安全&#xff0c;避免出现数据竞争等问题。 对象创建&#xff1a;如果在单例对象的构造函数…...

使用MAT进行内存分析,并找到OOM问题

前言 在处理一次现场问题时&#xff0c;发现服务还在运行&#xff0c;但是出现假死情况&#xff0c;后通过分析GC日志以及使用MAT分析确定问题是内存溢出OutOfMemery(OOM)&#xff1b;这里只记录MAT分析学习过程,最近工作忙&#xff0c;补记录。 GC日志分析 首先&#xff0c;如…...

初识Python

目录初识Python1.Python简介Python的优缺点Python的应用领域2.安装Python解释器Windows环境Linux环境macOS环境3.运行Python程序确认Python的版本编写Python源代码运行程序代码中的注释4.Python开发工具IDLE - 自带的集成开发工具IPython - 更好的交互式编程工具Sublime Text -…...

tmux终端复用软件

一、安装[rootpool-100-1-1-159 test]# yum install tmux [rootpool-100-1-1-159 test]# yum search tmux Repository extras is listed more than once in the configuration Last metadata expiration check: 0:33:52 ago on Fri 03 Mar 2023 09:10:34 AM CST.Name Exactly M…...

IO详解(文件,流对象,一些练习)

目录 文件 文件概念 文件的路径 路径有俩种表示风格 文件类型 如何区分文本文件还是二进制文件? java对文件的操作 File类中的一些方法 流对象 流对象的简单概念 java标准库的流对象 1.字节流,(操作二进制数据的) 2.字符流 (操作文本数据的) 流对象最核心的四个…...

SpringCloud全家桶— — 【1】eureka、ribbon、nacos、feign、gateway

SpringCloud全家桶— — 组件搭建 1 Eureka 1.1 Eureka-server 创建eureka-server的SpringBoot项目 ①导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId…...

【线程安全篇】

线程安全之原子性问题 x &#xff0c;在字节码文件中对应多个指令&#xff0c;多个线程在运行多个指令时&#xff0c;就存在原子性、可见性问题 赋值 多线程场景下&#xff0c;一个指令如果包含多个字节码指令&#xff0c;那么就不再是原子操作。因为赋值的同时&#xff0c…...

错误:EfficientDet网络出现“No boxes to NMS“并且mAP:0.0的解决方案

近日&#xff0c;在使用谷歌新推出来的一个网络EfficientDet进行目标检测训练自己的数据集的时候&#xff0c;出现了如下错误&#xff1a; 其中项目开源地址是&#xff1a;https://github.com/toandaominh1997/EfficientDet.Pytorch 上面截图中的1和2代表我的类别名称。读者可…...

python的opencv操作记录13——区域生长及分水岭算法

文章目录图像区域基本算法——形态学运算腐蚀与膨胀开运算与闭运算opencv中的形态学运算距离计算——distanceTransform函数连通域连通的定义计算连通域——connectedComponents连通域实验基于区域的分割区域生长算法自定义一个最简单区域生长算法实现区域分割一般区域分割open…...

一文看懂网上下单的手机流量卡为什么归属都是随机的!

最近很多网上下单的小伙伴们心中似乎都有一个疑问。那就是网上很多手机卡、流量卡都不能自选号码和归属地&#xff0c;就算能自选号码&#xff0c;归属地也是随机的而且很多都不会跟你说具体的城市&#xff0c;这是为什么呢&#xff1f;莫非其中有什么不可告人的秘密吗?小伙伴…...

python Pytest生成alluer测试报告的完整教程

1.下载allure包到本地&#xff0c;解压 网上很多资料&#xff0c;这边不提供了 2.配置环境变量 将上面解压后bin文件的路径复制&#xff0c;添加到环境变量Path下 3.验证环境变量配置是否功 在cmd中输入allure&#xff0c;回车 。查看allure是否成功&#xff1a; 4.pyc…...

4-spring篇

ApplicationContext refresh的流程 12个步骤 prepareRefresh 这一步创建和准备了Environment对象&#xff0c;并赋值给了ApplicationContext的成员变量 要理解Environment对象的作用 obtainFreshBeanFactory ApplicationContext 里面有一个成员变量&#xff0c;Beanfactory b…...

提升 Web 应用程序的性能:如何使用 JavaScript 编写缓存服务

缓存是一种重要的优化技术&#xff0c;用于加速数据访问和降低服务器负载。缓存存储经常访问的数据&#xff0c;以便在需要时可以快速检索。在本文中&#xff0c;我们将探索如何使用简单的数据结构在 JavaScript 中编写缓存服务。 编码缓存服务的第一步是定义将用于访问缓存的…...

供应商绩效管理指南:挑战、考核指标与管理工具

管理和优化供应商绩效既关键又具有挑战性。要知道价格并不是一切&#xff0c;如果你的供应商在商定的价格范围内向你开具发票&#xff0c;但服务达不到标准或货物不合格&#xff0c;你也无法达到节约成本的目标。 供应商绩效管理可以深入了解供应商可能带来的风险&#xff0c…...

干货文稿|详解深度半监督学习

分享嘉宾 | 范越文稿整理 | William嘉宾介绍Introduction to Semi-Supervised Learning传统机器学习中的主流学习方法分为监督学习&#xff0c;无监督学习和半监督学习。这里存在一个是问题是为什么需要做半监督学习&#xff1f;首先是希望减少标注成本&#xff0c;因为目前可以…...

信箱|邮箱系统

技术&#xff1a;Java、JSP等摘要&#xff1a;在经济全球化和信息技术飞速发展的今天&#xff0c;通过邮件收发进行信息传递已经成为主流。目前&#xff0c;基于B/S&#xff08;Browser/Server&#xff09;模式的MIS&#xff08;Management information system&#xff09;日益…...

JS数组拓展

1、Array.from Array.from 方法用于将两类对象转为真正的数组&#xff1a; 类似数组的对象,所谓类似数组的对象&#xff0c;本质特征只有一点&#xff0c;即必须有length属性。 因此&#xff0c;任何有length属性的对象&#xff0c;都可以通过Array.from方法转为数组 和 可遍历…...

一道很考验数据结构与算法的功底的笔试题:用JAVA设计一个缓存结构

我在上周的笔试中遇到了这样一道题目&#xff0c;觉得有难度而且很考验数据结构与算法的功底&#xff0c;因此Mark一下。 需求说明 设计并实现一个缓存数据结构: 该数据结构具有以下功能&#xff1a; get(key) 如果指定的key存在于缓存中&#xff0c;则返回与该键关联的值&am…...

(10)C#传智:命名空间、String/StringBuilder、指针、继承New(第10天)

内容开始多了&#xff0c;慢品慢尝才有滋味。 一、命名空间namespace 用于解决类重名问题&#xff0c;可以看作类的文件夹. 若代码与被使用的类&#xff0c;与当前的namespace相同&#xff0c;则不需要using. 若namespace不同时&#xff0c;调用的方法&#xff1a…...

基于Jetson Tx2 Nx的Qt、树莓派等ARM64架构的Ptorch及torchvision的安装

前提 已经安装好了python、pip及最基本的依赖库 若未安装好点击python及pip安装请参考这篇博文 https://blog.csdn.net/m0_51683386/article/details/129320492?spm1001.2014.3001.5502 特别提醒 一定要先根据自己板子情况&#xff0c;找好python、torch、torchvision的安…...

PX4飞控开发实战指南:从环境搭建到自主飞行

PX4飞控开发实战指南&#xff1a;从环境搭建到自主飞行 【免费下载链接】PX4-Autopilot PX4 Autopilot Software 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Autopilot 一、认知铺垫&#xff1a;无人机大脑如何工作&#xff1f; 你是否好奇无人机如何在空中保持…...

【STM32-HAL库】火焰传感器实战:从原理到智能火灾预警系统搭建(基于STM32F407ZGT6)

1. 火焰传感器原理与选型指南 火焰传感器作为火灾预警系统的"眼睛"&#xff0c;其核心原理是利用光电效应检测火焰特有的光谱特征。我经手过的工业项目中&#xff0c;90%的火灾误报都源于传感器选型不当。市面上常见的火焰传感器主要分为三类&#xff1a; 红外型&…...

用格子玻尔兹曼方法 - 浸没边界法模拟圆柱绕流(LBM - IBM in C++)

格子玻尔兹曼方法-浸没边界法模拟圆柱绕流 LBM- IBM &#xff08;C&#xff09;在计算流体力学&#xff08;CFD&#xff09;的领域里&#xff0c;格子玻尔兹曼方法&#xff08;Lattice Boltzmann Method, LBM&#xff09;和浸没边界法&#xff08;Immersed Boundary Method, IB…...

智能排错助手:让快马AI分析你的openclaw安装错误并生成解决方案

最近在折腾openclaw这个工具时&#xff0c;遇到了不少安装报错的问题。作为一个经常在各类开发环境中摸爬滚打的程序员&#xff0c;我发现这类开源工具的安装过程往往隐藏着不少坑。不过这次尝试用AI辅助诊断后&#xff0c;整个排错效率提升了不少&#xff0c;这里记录下我的实…...

Excel 技巧:一键批量填充空值

&#x1f680; 操作步骤选中区域首先&#xff0c;用鼠标选中包含空值的目标数据区域。定位空值按下快捷键 Ctrl G 打开“定位”对话框&#xff1a;点击左下角的 「定位条件...」。选择 「空值」。点击「确定」。✅ 此时&#xff0c;区域内所有空白单元格已被高亮选中。输入公式…...

HunyuanVideo-Foley入门指南:infer.py命令行参数全量说明与组合技巧

HunyuanVideo-Foley入门指南&#xff1a;infer.py命令行参数全量说明与组合技巧 1. 环境准备与快速部署 HunyuanVideo-Foley是一款强大的视频与音效生成工具&#xff0c;基于RTX 4090D 24GB显存和CUDA 12.4深度优化。在开始使用前&#xff0c;请确保您的硬件配置满足以下要求…...

多平台网络资源捕获工具:突破下载限制的技术实现与场景化应用

多平台网络资源捕获工具&#xff1a;突破下载限制的技术实现与场景化应用 【免费下载链接】res-downloader 资源下载器、网络资源嗅探&#xff0c;支持微信视频号下载、网页抖音无水印下载、网页快手无水印视频下载、酷狗音乐下载等网络资源拦截下载! 项目地址: https://gitc…...

hgproxy偶发性无法连接

文章目录环境症状问题原因解决方案环境 系统平台&#xff1a;银河麒麟 &#xff08;鲲鹏&#xff09; 版本&#xff1a;4.5.8 症状 hgproxy 4.0.33.3 出现偶发性无法连接现象&#xff0c;经过几分钟或几十秒或更长时间会自动恢复正常&#xff1b;psql 连接数据库端口正常&am…...

告别爆显存!在16G显卡上高效训练SDXL LORA的完整配置流程

16G显卡极限优化&#xff1a;SDXL LORA训练全流程实战指南 引言 当你手握一块RTX 4060 Ti或4070这样的16G显存显卡&#xff0c;想要尝试SDXL LORA训练时&#xff0c;是否常被爆显存的恐惧支配&#xff1f;别担心&#xff0c;这不是硬件性能的终点&#xff0c;而是优化艺术的起点…...

如何用LuckyLilliaBot在5分钟内构建QQ机器人:OneBot 11协议完全指南

如何用LuckyLilliaBot在5分钟内构建QQ机器人&#xff1a;OneBot 11协议完全指南 【免费下载链接】LuckyLilliaBot NTQQ的OneBot API插件 项目地址: https://gitcode.com/gh_mirrors/li/LuckyLilliaBot 想要快速搭建一个功能强大的QQ机器人吗&#xff1f;LuckyLilliaBot为…...