在C#/NETC内核中的临时服务实例之间共享线程安全字段?
我需要在从.NETCore中的临时服务调用的函数之间共享一些锁(也称为“对象”字段)和常规数据字段。 当然,这些锁和字段应该以线程安全的方式声明 最好的方法是什么?我正在考虑单独的单身服务。我是否必须向声明的字段和锁添加一些关键字,以使它们是线程安全的在C#/NETC内核中的临时服务实例之间共享线程安全字段?,c#,multithreading,asp.net-core,.net-core,thread-safety,C#,Multithreading,Asp.net Core,.net Core,Thread Safety,我需要在从.NETCore中的临时服务调用的函数之间共享一些锁(也称为“对象”字段)和常规数据字段。 当然,这些锁和字段应该以线程安全的方式声明 最好的方法是什么?我正在考虑单独的单身服务。我是否必须向声明的字段和锁添加一些关键字,以使它们是线程安全的 我非常熟悉Java多线程,但到目前为止还没有在C#中使用过。这是我能想到的最简单的例子。它使用。您也可以使用。基本上,我解决了一个临时服务3次。然后启动两个线程,这将增加共享服务的价值 class Program { static asy
我非常熟悉Java多线程,但到目前为止还没有在C#中使用过。这是我能想到的最简单的例子。它使用。您也可以使用。基本上,我解决了一个临时服务3次。然后启动两个线程,这将增加共享服务的价值
class Program
{
static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ValueService>();
serviceCollection.AddTransient<Service>();
var provider = serviceCollection.BuildServiceProvider();
var serviceOne = provider.GetRequiredService<Service>();
var serviceTwo = provider.GetRequiredService<Service>();
var serviceThree = provider.GetRequiredService<Service>();
// Manipulate the same object 1500 times, from different threads.
var task1 = serviceOne.DoStuff(500);
var task2 = serviceTwo.DoStuff(500);
var task3 = serviceThree.DoStuff(500);
// Wait for all the threads to complete.
await Task.WhenAll(task1, task2, task3);
// Verify the result.
var valueService = provider.GetRequiredService<ValueService>();
Console.WriteLine(valueService.SomeValue);
Console.ReadKey();
}
}
internal class Service
{
private readonly ValueService _service;
public Service(ValueService service)
{
_service = service;
}
public Task DoStuff(int noOfTimes)
{
var tasks = new Task[noOfTimes];
for (int i = 0; i < noOfTimes; i++)
{
tasks[i] = Task.Run(() =>
{
Thread.Sleep(100);
_service.Increase();
});
}
return Task.WhenAll(tasks);
}
}
internal class ValueService
{
public void Increase()
{
// Use lock to make sure that only one thread is changing the field at the time.
// Remove the lock statement and you will notice some "unwanted" behaviour.
lock (_lock)
{
SomeValue++;
}
// Alternatively you can use Interlocked.Increment(SomeValue)
}
private readonly object _lock = new object();
public int SomeValue { get; private set; }
}
类程序
{
静态异步任务主(字符串[]args)
{
var servicecolection=新servicecolection();
serviceCollection.AddSingleton();
serviceCollection.AddTransient();
var provider=serviceCollection.BuildServiceProvider();
var serviceOne=provider.GetRequiredService();
var serviceTwo=provider.GetRequiredService();
var servicetree=provider.GetRequiredService();
//从不同线程操作同一对象1500次。
var task1=serviceOne.DoStuff(500);
var task2=service2.DoStuff(500);
var task3=servicetree.DoStuff(500);
//等待所有线程完成。
等待任务。WhenAll(任务1、任务2、任务3);
//验证结果。
var valueService=provider.GetRequiredService();
Console.WriteLine(valueService.SomeValue);
Console.ReadKey();
}
}
内部班级服务
{
私有只读ValueService \u服务;
公共服务(价值服务)
{
_服务=服务;
}
公共任务DoStuff(中午时分)
{
var tasks=新任务[中午];
for(int i=0;i
{
睡眠(100);
_服务增加();
});
}
返回任务。WhenAll(任务);
}
}
内部类价值服务
{
公共空间增加()
{
//使用lock确保一次只有一个线程在更改字段。
//删除lock语句,您将注意到一些“不想要的”行为。
锁
{
SomeValue++;
}
//或者,您可以使用Interlocked.Increment(SomeValue)
}
私有只读对象_lock=新对象();
public int SomeValue{get;private set;}
}
对于线程安全处理,您可以查看监视器
和锁定
-因为ValueService是一个单例,您不需要将_lock字段标记为静态。所有线程将使用相同的值,因为它是一个singleton@RichardBlewett是的,确实如此。我已经更新了示例。非常感谢。您是否可以评论一下:“get”操作线程是否一致,在这种情况下(因此,如果我尝试设置,get将获得其他线程正在设置的内容?),以及为什么没有使用volatile
?@AskarIbragimovvolatile
可以使用,但它不会替换lock
。关于volatile我建议你重新开始。当前,get
不是线程安全的,因为它可能返回另一个线程正在写入的值。你可能也想锁定它。您可以在get
和set
中使用相同的lock
。在这种情况下,您可能应该修改示例以包括读取时锁定。