1.常见的会引起资源冲突的
·文件系统资源:多个线程同时读取,写入或删除同一文件或目录时
·数据库资源: 多线程并发访问和修改同一数据库记录(缺乏事务控制或锁定机制),多个线程或进程使用数据库连接资源时,可能导致连接超时或连接耗尽。
·内存资源: 多线程同时访问或修改静态(全局)变量时可能引发竞争条件,导致数据不一致出错
·网络资源:同时范文或操作同一个网络套接字(如发送和接受数据)可能会引发冲突,导致数据包丢失或混乱;多个进程绑定同一端口等;
·硬件资源:多线程同时访问打印机,扫描仪可能会引起冲突。
·配置文件: 多线程同时读取或写入同一配置文件
·日志文件:多线程同时写入同一个日志文件
2.常用的解决资源冲突的方法
内存映射文件(内容映射到进程的虚拟地址中)、临时文件缓存(本地副本文件)、内存流(内存中(堆)划一块区域存储临时文件)
//防止资源占用,使用内存流存储数据
byte[] pixels;
int width, height;
using (Bitmap bitmap = new Bitmap(patientMsg.PicturePath))
{
width = bitmap.Width; // 保存宽度信息
height = bitmap.Height; // 保存高度信息
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); // 将图片保存到内存流
pixels = ms.ToArray(); // 将图片数据转换为字节数组,传输和存储本地等方便,需要再转为bitmap
}
}
MemoryByteBuffer buffer = new MemoryByteBuffer(pixels);
适用场景:文件系统资源
访问非常大的文件(如图像文件),如果是很小的文件,用锁就行了
通过async和await实现异步网络操作,在不阻塞主线程的情况下处理多个网络请求
适用场景: 网络资源,数据库资源
对于数据库资源可能存在的高并发访问的场景,应该使用数据库连接池会更好
在Program.cs 配置
// 添加DbContext服务,配置连接池,可以应对高并发
services.AddDbContextPool<AppDbContext>(options =>
options.UseSqlServer(connectionString));
// 添加DbContext服务,不配置连接池
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
适用场景:数据库资源
EFCore是实现了优秀的连接池管理
使用各种锁(互斥锁,读写锁)来禁止多线程同时访问同一资源
static int sharedResource = 0;
static readonly object mutex = new object();
static void Increment()
{
for (int i = 0; i < 10000; i++)
{
lock (mutex)
{
sharedResource++;
}
}
}
适用场景:内存资源
锁内的执行步骤应该较为简单,且执行不需要耗费太长时间。
单例模式只有一个全局实例负责配置文件的操作,从而避免多个实例同时访问配置文件可能带来的竞争问题。
public class DicomLogger
{
private static readonly Lazy<DicomLogger> instance = new Lazy<DicomLogger>(() => new DicomLogger());
private string logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs", "log.txt");//路径
private DicomLogger()
{
string logDirectory = Path.GetDirectoryName(logFilePath);
if (!Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.RollingFile(logFilePath).CreateLogger();
}
}
public class DicomConfigurationManager
{
private static readonly Lazy<DicomConfigurationManager> instance = new Lazy<DicomConfigurationManager>(() => new DicomConfigurationManager()); //仅首次访问instance实例化
private DicomConfigData configData;
private string pacsConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PacsConfig.ini");
private readonly object _lock = new object();
private DicomConfigurationManager()
{
configData = LoadConfiguration() ?? new DicomConfigData();
}
}
适用场景:硬件资源、配置文件、日志文件
注意单例的实现方式。