在C#中的线程之间传递数据 [英] Passing data between threads in c#

查看:218
本文介绍了在C#中的线程之间传递数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了有关我的问题的几个问题,但是我仍然无法独自解决这个问题,因此我将尝试在这里提出.我将粘贴代码,以便更容易解释.

I've found few questions concerning my problem but still, I couldn't hande with this on my own so I'll try to ask in here. I'll paste the code so I think it will be easier to explain.

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中对其进行更改? 感谢您的回答:)
    • I would like to have an acces from method StartCalculation which started in different thread. I'd like to access that int list from Form1 (10 elements after 10 secs, 20 elements after 20 secs and so). Is that possible?
    • Would creating list in Form1() and then changing it in StartCalculation be possible? Thanks for the answers :)
    • 为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);
          }
      
      }  
      
      }
      

      我正在制作游戏机器人.我希望它在不同的线程中读取游戏的内存(更改内存列表),然后用其他几种方法(在不同的线程中)读取该列表,并根据内存值执行游戏操作.它可以工作(或似乎可以),但是如果您说它可能不安全,那么我想使其安全.

      I'm making game bot. I want it to read game's memory in a different thread (changing memory list) and then, with few other methods (in different threads) I'd like to read from that list and do game actions depending on the memory values. It works (or just seem to be) but if You say it might be unsafe, I'd like to make it safe.

      希望我没有通过将其粘贴到这里来使自己变得愚蠢.

      Hope I haven't made fool out of myself by pasting it here.

      推荐答案

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

      You need some form of a synchronization mechanism to modify objects between multiple threads. If you don't use a specialized thread safe collection (these are available in .NET 4), you need to lock using a monitor.

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

      Usually, a more appropriate collection type for the producer/consumer pattern is a Queue (a FIFO collection), instead of a 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();
          }
      
      }
      

      在使用者线程中,您需要获取项目并进行处理:

      And in the consumer thread, you need to fetch the item and process it:

      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,从而无需在访问时锁定,并简化了代码:

      Starting with .NET 4, there is a ConcurrentQueue<T> collection, a thread-safe FIFO, which removes the need to lock while accessing it and simplifies the code:

      ConcurrentQueue

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

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

      Finally, if you only wish that your consumer thread gets items in chunks periodically, you would change this to:

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

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

      此模式非常有用,可以将其抽象为一个通用类,该类将生产和使用委托给外部代码.使其具有通用性将是一个很好的练习.

      This pattern is so useful that it's nice to abstract it into a generic class which delegates producing and consuming to external code. It would be a good exercise to to make it generic.

      您还将需要一个Stop方法,该方法可能会设置一个volatile bool标志,指示该时间停止了,然后将其设置为取消暂停使用者并使其结束.我将把它留给您作为练习.

      You will also need a Stop method which will probably set a volatile bool flag indicating that it's time to stop, and then set the signal to unpause the consumer and allow it to end. I will leave this to you as an exercise.

      这篇关于在C#中的线程之间传递数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆