在c#中的线程之间传递数据

本文关键字:数据 之间 线程 | 更新日期: 2023-09-27 18:21:32

我发现了一些关于我的问题的问题,但我仍然无法独自处理,所以我会尝试在这里提问。我会粘贴代码,这样我想解释起来会更容易。

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的acces。我想从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);
    }
}  
}

我正在制作游戏机器人。我想让它在不同的线程中读取游戏的内存(更改内存列表),然后,通过一些其他方法(在不同的螺纹中),我想从该列表中读取并根据内存值执行游戏操作。它是有效的(或者看起来是有效的),但如果你说它可能不安全,我想让它安全。

希望我把它贴在这里没有出丑。

在c#中的线程之间传递数据

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

通常,生产者/消费者模式更合适的集合类型是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
    }
}

从.NET4开始,有一个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
        }
    }
}

最后,如果你只希望你的消费者线程周期性地获取大块的项目,你可以将其更改为:

具有阈值的并发队列(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
        }
    }
}

这种模式非常有用,因此将其抽象为一个泛型类是很好的,该类将生成和消费委托给外部代码。将其通用化将是一个很好的练习。

您还需要一个Stop方法,该方法可能会设置volatile bool标志,指示是时候停止了,然后将信号设置为取消暂停使用者并允许其结束。我将把这个留给你练习。

在这种情况下使用

label.Invoke(..., textForLabel)