线程之间的共享方法

时间:2020-04-05 15:34:51

标签: c# multithreading task-parallel-library

我有这样的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

如果我想找到一种方法来处理第一个线程并阻塞其他所有线程,并且在第一个线程的方法调用完成后,将方法结果发送给其他线程,并取消它们,以防止它们调用{再次{1}}。

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

2 个答案:

答案 0 :(得分:2)

似乎您需要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>实例。

答案 1 :(得分:0)

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

The purpose of lock statement is

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