我制作了一个示例Consumer / Producer线程应用程序,因此我可以学习如何正确使用它。
我希望它允许一个线程向GUI线程发送命令,用内容更新GUI。
我有它的工作,但有一个小问题。 GUI线程是我的消费者线程,所以我总是检查新命令(使用while循环)。问题是因为这个while循环,GUI永远不会显示,因为它总是停留在while循环中。请注意,字符串Queue最终将被更复杂的对象(包含数据和命令类型的对象)替换。
我不确定如何让GUI线程在不中断GUI功能的情况下使用命令。我做错了吗?
这是我的Form1.cs代码(表单只包含1个RichTextBox,用于显示名为OutputBox的输出)。
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace MultiThreading
{
class ThreadCommandQueue
{
public static ThreadCommandQueue instance = new ThreadCommandQueue();
private Queue<string> m_queue;
private Object m_lock;
public static ThreadCommandQueue GetInstance()
{
return instance;
}
private ThreadCommandQueue()
{
m_queue = new Queue<string>();
m_lock = new Object();
}
public void Add(
string data_to_add)
{
lock (m_lock)
{
m_queue.Enqueue(data_to_add);
}
}
public string Get()
{
lock (m_lock)
{
if (m_queue.Count > 0)
{
return m_queue.Dequeue();
}
return null;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void PopulateThreadCommandQueue()
{
int i = 0;
while(true)
{
ThreadCommandQueue.GetInstance().Add("Item #: " + i.ToString());
i++;
}
}
private void Form1_Load(object sender, EventArgs e)
{
// Create the Command Queue....
ThreadCommandQueue.GetInstance();
// Create a Testing Producer Thread
Thread ProducerThread = new Thread(PopulateThreadCommandQueue);
ProducerThread.Start();
// The GUI thread is the Consumer, so keep checking the CommandQueue for data...
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(latest != null)
{
OutputBox.Text += latest + "\n";
}
}
}
}
}
答案 0 :(得分:2)
使用ConcurrentQueue。因此,从Queue添加和获取不需要锁定。
此外,您实时不会从UI线程(循环时)连续接收命令。如果您有这样的场景,请使用单独的线程来接收结果。
然后,从接收器线程,您可以使用Invoke命令更新UI,如下所示。
//This method called from receiver thread
public void UpdateForm(Data d)
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => this.UpdateFormUI(r)));
}
else
{
this.UpdateFormUI(data)
}
}
public void UpdateFormUI(Data d)
{
//Does actual ui update
}
答案 1 :(得分:0)
好的,这里的问题是你需要一直轮询消息循环以使GUI工作,你还需要一直轮询你的IPC命令队列以使你的命令工作,你需要这个轮询发生在同一时间在同一个线程上。
有多种方法可以解决这个问题,但最简单的方法是处理消息循环,当没有任何内容需要处理时,请执行IPC命令队列处理。对于WinForms应用程序,这将是:
public Form1()
{
InitializeComponent();
Application.Idle += (sender, eargs) => ProcessCommands();
}
private void ProcessCommands()
{
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(string.IsNullOrEmpty(latest)) return;
OutputBox.Text += latest + "\n";
}
}