线程间共享方法
Share method between threads
我有一个 Func
这样的:
int loopMax = 10, taskMax = 10;
int executionCounter = 0;
Func<int> calculator = new Func<int>(() =>
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
result = 0;
result += i;
}
return result;
});
可以被多线程调用。例如像这样:
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _=calculator());
}
Task.WaitAll(tasks);
我需要在所有线程之间共享 calculator
函数,并使该函数只被调用一次。事实上,运行 之后的 executionCounter
变量的值应该保持为 1,并且所有线程都应该具有相同的 return 值。
更新 1
我想我可以解决这个问题,如果我找到一种方法来为第一个线程提供服务并阻塞所有其他线程,并且在第一个线程的方法调用完成后,将方法结果通知其他线程并取消它们,以防止它们再次呼叫 calculator
。
在方法内部使用 lock
也不是我想要的,因为在那种情况下,计算器再次被调用多次...
看起来你想要的是你的Calculator
方法可以被任何线程执行,但是这个方法应该只执行一次。如果为真,那么我们将使用 lock
语句。
The purpose of lock statement is:
The lock statement acquires the mutual-exclusion lock for a given
object, executes a statement block, and then releases the lock
一个例子:
static object lockCalculatorMethod = new object();
static int executionCounter = 0;
static int loopMax = 10;
static int taskMax = 10;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = Calculator());
}
Task.WhenAll(tasks);
}
和计算器方法:
static int Calculator()
{
lock (lockCalculatorMethod)
{
if (executionCounter < 1)
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
{
result = 0;
result += i;
}
}
return result;
}
else
return -1;
}
}
更新:
如果你想缓存结果并避免在被其他线程调用时重新计算,那么你可以use threadSafe collection ConcurrentQueue<T>
并且只从这个集合中获取项目:
static object lockCalculatorMethod = new object();
static ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
static int executionCounter = 0;
static int loopMax = 7;
static int taskMax = 7;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() =>
{
var result = Calculator();
Console.WriteLine(result);
});
}
Task.WaitAll(tasks);
}
和Calculator
方法:
static int Calculator()
{
int result = 0;
lock (lockCalculatorMethod)
{
int lockResult = 0;
if (executionCounter < 1)
{
executionCounter++;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
lockResult += i;
}
queue.Enqueue(lockResult);
}
}
queue.TryPeek(out result);
return result;
}
看来您需要 Lazy<T>
class。 class 提供对惰性初始化的支持。以下是您的使用方法:
Lazy<int> lazyCalculator = new Lazy<int>(calculator);
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = lazyCalculator.Value);
}
Task.WaitAll(tasks);
构造 Lazy
实例时,它可以采用可选的 LazyThreadSafetyMode
参数。此参数的默认值为 ExecutionAndPublication
,其行为如下所述:
Locks are used to ensure that only a single thread can initialize a Lazy<T>
instance in a thread-safe manner.
我有一个 Func
这样的:
int loopMax = 10, taskMax = 10;
int executionCounter = 0;
Func<int> calculator = new Func<int>(() =>
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
result = 0;
result += i;
}
return result;
});
可以被多线程调用。例如像这样:
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _=calculator());
}
Task.WaitAll(tasks);
我需要在所有线程之间共享 calculator
函数,并使该函数只被调用一次。事实上,运行 之后的 executionCounter
变量的值应该保持为 1,并且所有线程都应该具有相同的 return 值。
更新 1
我想我可以解决这个问题,如果我找到一种方法来为第一个线程提供服务并阻塞所有其他线程,并且在第一个线程的方法调用完成后,将方法结果通知其他线程并取消它们,以防止它们再次呼叫 calculator
。
在方法内部使用 lock
也不是我想要的,因为在那种情况下,计算器再次被调用多次...
看起来你想要的是你的Calculator
方法可以被任何线程执行,但是这个方法应该只执行一次。如果为真,那么我们将使用 lock
语句。
The purpose of lock statement is:
The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock
一个例子:
static object lockCalculatorMethod = new object();
static int executionCounter = 0;
static int loopMax = 10;
static int taskMax = 10;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = Calculator());
}
Task.WhenAll(tasks);
}
和计算器方法:
static int Calculator()
{
lock (lockCalculatorMethod)
{
if (executionCounter < 1)
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
{
result = 0;
result += i;
}
}
return result;
}
else
return -1;
}
}
更新:
如果你想缓存结果并避免在被其他线程调用时重新计算,那么你可以use threadSafe collection ConcurrentQueue<T>
并且只从这个集合中获取项目:
static object lockCalculatorMethod = new object();
static ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
static int executionCounter = 0;
static int loopMax = 7;
static int taskMax = 7;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() =>
{
var result = Calculator();
Console.WriteLine(result);
});
}
Task.WaitAll(tasks);
}
和Calculator
方法:
static int Calculator()
{
int result = 0;
lock (lockCalculatorMethod)
{
int lockResult = 0;
if (executionCounter < 1)
{
executionCounter++;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
lockResult += i;
}
queue.Enqueue(lockResult);
}
}
queue.TryPeek(out result);
return result;
}
看来您需要 Lazy<T>
class。 class 提供对惰性初始化的支持。以下是您的使用方法:
Lazy<int> lazyCalculator = new Lazy<int>(calculator);
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = lazyCalculator.Value);
}
Task.WaitAll(tasks);
构造 Lazy
实例时,它可以采用可选的 LazyThreadSafetyMode
参数。此参数的默认值为 ExecutionAndPublication
,其行为如下所述:
Locks are used to ensure that only a single thread can initialize a
Lazy<T>
instance in a thread-safe manner.