如何识别 C# 中的关键部分?
How to identify critical sections in C#?
编辑:这与其他人建议的 post "CRITICAL_SECTION in c#" 不同。这个post是关于如何识别需要在关键部分完成的代码。建议的副本 post 询问如何将 Windows OS API 用于关键部分。甚至不一样。
学习多线程和异步代码。在识别关键部分时遇到一些困难。不太确定上下文切换之间共享的内容和独占的内容。值类型和引用类型的处理方式之间的差异。局部变量vs.外部变量vs.传入的参数是否在一个方法中处理。
下面是一些专门用于此练习的代码。假设有多个线程可以调用具有不同参数值的方法。我还在方法之外添加了几个变量。
首先让我们看看一些假设是否正确。 CS是"critical section"为了方便。
++localX
需要在 CS 中,因为它是一个局部变量。 int localX = 0
没问题,因为这在 C# 中是原子的。即,一个线程在初始声明变量时不会将另一个线程的 localX
设置回 0
。
++externalX
需要在 CS 中,因为它是共享资源。并且需要声明为 volatile,否则线程可能会作用于缓存的值并最终得到错误的结果。
externalParms.Add( parms[0] );
需要在 CS 中,因为 Add
方法不是线程安全的,它是共享资源。也应该声明为 volatile。
myList[localX] = externalX;
需要在 CS 中,因为索引器不是线程安全的,而且它是一个局部变量。
问题
- ADO.NET代码呢?
using (var command = new SqlCommand(spName, connection))
我是否需要担心线程将其 spName
放入另一个线程 command
对象?
command.Parameters.AddRange(parms);
我正在向集合中添加值。这不是线程安全的,需要在 CS 中?
await command.ExecuteNonQueryAsync();
command
是局部变量。文档没有说明 ExecuteNonQueryAsync()
方法是线程安全的。 CS 还是没有 CS?
parms[0].Value = rnum;
需要在 CS 中吗?
任意码:
int externalX = 10;
List<SqlParameter> externalParms = new List<SqlParameter>();
internal async Task SampleExecuteNonQueryAsync(string spName, SqlParameter[] parms)
{
int localX = 0;
List<int> myList = new List<int>() { -1,-1};
Random rnd = new Random();
using (var connection = new SqlConnection(_connString))
{
await connection.OpenAsync();
using (var command = new SqlCommand(spName, connection))
{
++localX;
int rnum = rnd.Next(1, 100);
parms[0].Value = rnum;
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(parms);
await command.ExecuteNonQueryAsync();
++externalX;
}
}
myList[localX] = externalX;
externalParms.Add( parms[0] );
}
我觉得你很糊涂,想太多了。
任何基于 'stack' 的变量(即局部变量)都是 'per-thread',因此不需要为它们锁定任何东西,每个线程都有一个完全独立的线程。
如果您担心超过 1 个线程将访问 externalParms
,请使用为此目的制作的集合之一:https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/
编辑:这与其他人建议的 post "CRITICAL_SECTION in c#" 不同。这个post是关于如何识别需要在关键部分完成的代码。建议的副本 post 询问如何将 Windows OS API 用于关键部分。甚至不一样。
学习多线程和异步代码。在识别关键部分时遇到一些困难。不太确定上下文切换之间共享的内容和独占的内容。值类型和引用类型的处理方式之间的差异。局部变量vs.外部变量vs.传入的参数是否在一个方法中处理。
下面是一些专门用于此练习的代码。假设有多个线程可以调用具有不同参数值的方法。我还在方法之外添加了几个变量。
首先让我们看看一些假设是否正确。 CS是"critical section"为了方便。
++localX
需要在 CS 中,因为它是一个局部变量。int localX = 0
没问题,因为这在 C# 中是原子的。即,一个线程在初始声明变量时不会将另一个线程的localX
设置回0
。++externalX
需要在 CS 中,因为它是共享资源。并且需要声明为 volatile,否则线程可能会作用于缓存的值并最终得到错误的结果。externalParms.Add( parms[0] );
需要在 CS 中,因为Add
方法不是线程安全的,它是共享资源。也应该声明为 volatile。myList[localX] = externalX;
需要在 CS 中,因为索引器不是线程安全的,而且它是一个局部变量。
问题
- ADO.NET代码呢?
using (var command = new SqlCommand(spName, connection))
我是否需要担心线程将其spName
放入另一个线程command
对象?command.Parameters.AddRange(parms);
我正在向集合中添加值。这不是线程安全的,需要在 CS 中?await command.ExecuteNonQueryAsync();
command
是局部变量。文档没有说明ExecuteNonQueryAsync()
方法是线程安全的。 CS 还是没有 CS?
parms[0].Value = rnum;
需要在 CS 中吗?
任意码:
int externalX = 10;
List<SqlParameter> externalParms = new List<SqlParameter>();
internal async Task SampleExecuteNonQueryAsync(string spName, SqlParameter[] parms)
{
int localX = 0;
List<int> myList = new List<int>() { -1,-1};
Random rnd = new Random();
using (var connection = new SqlConnection(_connString))
{
await connection.OpenAsync();
using (var command = new SqlCommand(spName, connection))
{
++localX;
int rnum = rnd.Next(1, 100);
parms[0].Value = rnum;
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(parms);
await command.ExecuteNonQueryAsync();
++externalX;
}
}
myList[localX] = externalX;
externalParms.Add( parms[0] );
}
我觉得你很糊涂,想太多了。
任何基于 'stack' 的变量(即局部变量)都是 'per-thread',因此不需要为它们锁定任何东西,每个线程都有一个完全独立的线程。
如果您担心超过 1 个线程将访问 externalParms
,请使用为此目的制作的集合之一:https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/