c# - c#线程间数据传递

标签 c# multithreading

我发现了一些关于我的问题的问题,但我仍然无法独自解决这个问题,所以我会尝试在这里提问。我会粘贴代码,这样我认为它会更容易解释。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Thread thread = new Thread(new ThreadStart(StartCalculation));
        thread.Start();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }


    public void StartCalculation()
    {
        List<int> numbers = new List<int>();
        for (int i = 0; i <= 100; i++)
        {
            numbers.Add(i);
            string textForLabel = i.ToString();
            label.SafeInvoke(d => d.Text = textForLabel);
        }

    }  
}
  • 我想从在不同线程中启动的方法 StartCalculation 获得一个访问权限。我想从 Form1 访问该 int 列表(10 秒后 10 个元素,20 秒后 20 个元素等等)。这可能吗?
  • 是否可以在 Form1() 中创建列表,然后在 StartCalculation 中更改它? 感谢您的回答:)

为 Groo-/- 编辑

public partial class Form1 : Form
{

List<int> list = new List<int>(); // list of int values from game's memory

public Form1()
{
    InitializeComponent();
    Thread thread = new Thread(new ThreadStart(refreshMemory));
    thread.Start();
    Thread thread2 = new Thread(new ThreadStart(checkMemory));
    thread2.Start();
}

private void Form1_Load(object sender, EventArgs e)
{
}

public void refreshMemory()
{        
    while (true)
    {
     // ... refresh game's memory and then, refresh list //
    Thread.Sleep(100);
    }
}  

public void checkMemory()
{

    while (true)
    {
     // eg. if (list[0] == 5) {game:: move_right()}// 
    Thread.Sleep(100);
    }

}  

}

我正在制作游戏机器人。我希望它在不同的线程(更改内存列表)中读取游戏的内存,然后,我想使用其他一些方法(在不同的线程中)从该列表中读取并根据内存值执行游戏操作。它有效(或似乎有效),但如果您说它可能不安全,我想让它安全。

希望我没有把它粘贴在这里让自己出丑。

最佳答案

您需要某种形式的同步机制来在多个线程之间修改对象。如果您不使用专门的线程安全集合(这些在 .NET 4 中可用),则需要使用监视器进行锁定。

通常,更适合生产者/消费者模式的集合类型是 Queue (一个 FIFO 集合),而不是 List :

带显式锁定的普通队列

private readonly object _lock = new object();
private readonly Queue<Item> _queue = new Queue<Item>();
private readonly AutoResetEvent _signal = new AutoResetEvent();

void ProducerThread()
{
    while (ShouldRun) 
    { 
        Item item = GetNextItem();

        // you need to make sure only
        // one thread can access the list
        // at a time
        lock (_lock)
        {
            _queue.Enqueue(item);
        }

        // notify the waiting thread
        _signal.Set();
    }

}

并且在消费者线程中,您需要获取项目并处理它:

void ConsumerThread()
{
    while (ShouldRun)
    {
        // wait to be notified
        _signal.Wait();

        Item item = null;

        do
        { 
           item = null;

           // fetch the item,
           // but only lock shortly
           lock (_lock)
           {
               if (_queue.Count > 0)
                  item = _queue.Dequeue(item);
           }

           if (item != null)
           {
              // do stuff
           }            
        }
        while (item != null); // loop until there are items to collect
    }
}

从 .NET 4 开始,有一个 ConcurrentQueue<T> 集合,一个线程安全的 FIFO,在访问它时无需锁定并简化了代码:

并发队列

private readonly ConcurrentQueue<Item> _queue = new ConcurrentQueue<Item>();

void ProducerThread()
{
    while (ShouldRun) 
    { 
        Item item = GetNextItem();
        _queue.Enqueue(item);
        _signal.Set();
    }

}

void ConsumerThread()
{
    while (ShouldRun)
    {
        _signal.Wait();

        Item item = null;
        while (_queue.TryDequeue(out item))
        {
           // do stuff
        }
    }
}

最后,如果您只希望您的消费者线程定期获取 block 中的项目,您可以将其更改为:

具有阈值的 ConcurrentQueue(10 秒或 10 个项目)

private readonly ConcurrentQueue<Item> _queue = new ConcurrentQueue<Item>();

void ProducerThread()
{
    while (ShouldRun) 
    { 
        Item item = GetNextItem();
        _queue.Enqueue(item);

        // more than 10 items? panic!
        // notify consumer immediately

        if (_queue.Count >= 10)
           _signal.Set();
    }

}

void ConsumerThread()
{
    while (ShouldRun)
    {
        // wait for a signal, OR until
        // 10 seconds elapses
        _signal.Wait(TimeSpan.FromSeconds(10));

        Item item = null;
        while (_queue.TryDequeue(out item))
        {
           // do stuff
        }
    }
}

这种模式非常有用,可以很好地将其抽象为一个通用类,该类将生产和消费委托(delegate)给外部代码。使其通用化将是一个很好的练习。

您还需要一个 Stop可能会设置 volatile bool 的方法标志表明是时候停止了,然后设置信号以取消暂停消费者并允许它结束。我将把它留给你作为练习。

关于c# - c#线程间数据传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8999373/

相关文章:

c# - 如何更改图表系列颜色

c# - 需要使用C#刷新chrome浏览器

Ruby - 基于 Redis 的具有过期实现的互斥锁

c# - 错误回发 ASP.NET MVC 的模型列表

比较相同字符串时,C# IComparer 返回意外结果

c++ - boost 中是否有允许写入偏向锁定的工具?

python - 如何捕获多线程的异常?

c# - 为什么在使用 Parallel.ForEach 时主线程被阻塞

c++ - 有没有一种安全的方法可以让 std::thread 作为类的成员?

c# - 仅在构造函数中使用私有(private) setter 是否会使对象线程安全?