c#从不同线程共享变量访问



我使用静态变量来访问线程之间,但是需要很长时间才能获得它们的值。

上下文:我有一个静态类Results.cs,其中我存储两个运行的Process.cs实例的结果变量。

public static int ResultsStation0 { get; set; }
public static int ResultsStation1 { get; set; }

然后,同时调用两个流程实例的一个函数,初始值为ResultsStation0/1 = -1。

因为不是同时提供结果,所以函数检查两个结果是否都可用。快实例将设置结果并等待慢实例的结果。

void StationResult(){
Stopwatch sw = new Stopwatch();
sw.Restart();
switch (stationIndex) //Set the result of the station thread
{
case 0: Results.ResultsStation0 = 1; break;
case 1: Results.ResultsStation1 = 1; break;
}
//Waits to get the results of both threads
while (true)
{
if (Results.ResultsStation0 != -1 && Results.ResultsStation1 != -1)
{
break;
}
}
Trace_Info("GOT RESULTS " + stationIndex + "Time: " + sw.ElapsedMilliseconds.ToString() + "ms");

if (Results.ResultsStation0 == 1 && Results.ResultsStation1 == 1)
{
//set OK if both results are OK
Device.profinet.WritePorts(new Enum[] { NOK, OK },
new int[] { 0, 1 });
}
}

它可以工作,但问题是等待线程的sw值应该大于或小于1ms。我有时得到1毫秒,但大多数时候我的值高达80毫秒。我的问题是:如果它们共享相同的内存(我猜),为什么需要这么多?

这是访问线程间变量的正确方式吗?

不要使用这种方法。全局可变状态已经够糟糕的了。混合使用多个线程听起来像是代码不可维护的秘诀。由于根本没有同步,因此无法真正保证您的程序可能会完成。在单CPU系统上,你的循环将阻止任何实际工作的完成,直到调度程序选择一个工作线程来运行,甚至在多核系统上,你将浪费大量的CPU周期。

如果你真的想要全局变量,这些应该是一些可以信号操作的完成,即一个任务,或ManualResetEvent。这样你就可以摆脱可怕的旋转等待,实际上等待完成每个任务。

但我会强烈建议摆脱全局变量,只使用标准的基于任务的编程:

var result1 = Task.Run(MyMethod1);
var result2 = Task.Run(MyMethod2);
await Task.WhenAll(new []{result1, result2});

这样的代码更容易推理和理解。

多线程编程困难。有一堆新的方式可以打破你的程序,编译器不会帮助你。如果您甚至得到一个异常,您就很幸运了,在许多情况下,您将得到一个错误的结果。如果不走运,您只会在生产中得到不正确的结果,而不是在开发或测试中。所以你应该多读一些关于这个话题的书,这样你至少可以熟悉常见的危险和减轻它们的方法。

您正在使用标志作为信号,您有一个名为AutoResetEvent的类。

safe accesssynchronization之间存在差异。

  1. 为了安全访问(原子)的目的,你可以使用Interlocked
  2. 类对于同步,您可以使用基于mutex的解决方案-无论是自旋锁,屏障等…

看起来你需要一个同步机制,因为你依靠atomic行为来通知进程它已经完成了。

,对于C#,有async的方式来做事情,那就是调用await.
它是基于Task的,所以如果你可以重新设计你的流程使用Tasks而不是线程,它会更适合你。

明确一点——原子性意味着你一次执行调用。例如,这不是原子

int a = 0;
int b = a; //not atomic - read 'a' and then assign to 'b'.

我不会在一篇文章中教你所有关于c#线程的知识,所以我的建议是阅读MSDN上关于线程和任务的文章。

最新更新