C# 在线程和类之间共享变量

C# 在线程和类之间共享变量,c#,multithreading,C#,Multithreading,我创建了一个应用程序,其中包含一些数据,这些数据使用计时器定期更新。该类还包含一些公共函数,用于将数据传递给另一个类。下面是它的外观: private void OnTimer(object sender, ElapsedEventArgs status) { GetNewData(); } public void GetData(ref List<double> data, int index) { if (index < m_data.Length)

我创建了一个应用程序,其中包含一些数据,这些数据使用计时器定期更新。该类还包含一些公共函数,用于将数据传递给另一个类。下面是它的外观:

private void OnTimer(object sender, ElapsedEventArgs status)
{
    GetNewData();
}

public void GetData(ref List<double> data, int index)
{
    if (index < m_data.Length)
    {
        data = new List<double>(m_data[index]);
    }
    else
    {
       data = new List<double>();
    }
}
private void OnTimer(对象发送方,ElapsedEventArgs状态)
{
GetNewData();
}
public void GetData(参考列表数据,int索引)
{
if(索引
目前,我没有任何保护来确保函数GetData在被修改时不会访问数据。
您能告诉我保护共享数据的最佳方法吗?

您可以锁定代码。每个线程将等待您的lock语句,然后进入新数据创建的内部:

private void OnTimer(object sender, ElapsedEventArgs status)
{
    GetNewData();
}

object lockCheck = new object();
public void GetData(ref List<double> data, int index)
{
    lock(lockCheck)
{
    if (index < m_data.Length)
    {
        data = new List<double>(m_data[index]);
    }
    else
    {
       data = new List<double>();
    }
}
}
private void OnTimer(对象发送方,ElapsedEventArgs状态)
{
GetNewData();
}
对象锁定检查=新对象();
public void GetData(参考列表数据,int索引)
{
锁(锁止)
{
if(索引
您对更新数据的方式不太明确。如果您的
GetNewData
方法完全替换了
m_data
成员,则根本不需要锁。考虑这一点:

// this is the shared data
SomeDataType m_data;

// Method that reads the data
public void GetData(ref List<double> data, int index)
{
    // get a reference to the existing data
    var localData = m_data;

    // only work with the localData reference here
}

private void OnTimer(object sender, ElapsedEventArgs status)
{
    GetNewData();
}
使用这种技术,get方法和计时器无法相互干扰。如果在getter运行时调用了
GetNewData
,则没有问题,因为getter使用的是本地引用


唯一的潜在问题是,如果在运行
GetNewData
时调用getter,那么返回的值将来自旧列表。也就是说,可能是过时的数据。这是否是一个问题实际上是由您来决定的。

有专门为多个线程设计的集合,用于相互提供数据。您可以使用
BlockingCollection
,它是
ConcurrentQueue
的包装器,允许计时器生成数据,将其添加到队列中,然后让代码从该队列读取并处理结果。
BlockingCollection
将负责线程之间的所有同步。

查看一下“lock”语句我查看了一下锁,我想知道是否最好将它放在Get函数或计时器线程中?我看不到您的全部代码,但如果您是通过线程触发OnTimer的,那么它会自动启动把锁放在那里是有道理的。从这里我看到OnTimer只调用GetNewData方法。因此,在本例中,最好将代码放在GetData方法中,因为这是锁必须将线程放入队列的地方。如果要使用锁,则需要在两个位置使用它:在getter和setter中。我没有将所有代码放在一起,因为它很长,并且修改了几个变量。事实上,我有几个公共函数来检索每个数据。我会试着把计时器锁上。
private void GetNewData()
{
    var localData = /* create the data here */

    // replace the reference
    m_data = localData;
}