线程之间共享方法



我有一个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,并且所有线程都应具有相同的返回值。

更新1

我想如果我能找到一种方法来为第一个线程提供服务器,并每隔一个线程阻塞一次,并且在第一个线程的方法调用完成后,将方法结果发送给其他线程,并取消它们,以防止它们再次调用calculator,我就能解决这个问题。

在方法中使用lock也不是我想要的,因为在这种情况下,计算器会被多次调用。。。

您似乎需要Lazy<T>类。此类提供对延迟初始化的支持。以下是如何使用它:

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,行为描述如下:

锁用于确保只有一个线程可以以线程安全的方式初始化Lazy<T>实例。

您似乎希望Calculator方法可以由任何线程执行,但此方法只能执行一次。如果它是真的,那么我们将使用lock语句。

锁定语句的目的是:

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;
}
}

更新:

如果您想在其他线程调用时缓存结果并避免重新计算,那么您可以使用threadSafe集合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;
} 

最新更新