【发布时间】:2018-05-22 08:20:22
【问题描述】:
我制作了一个示例消费者/生产者线程应用程序,因此我可以学习如何正确使用它。
我希望它允许一个线程向 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";
}
}
}
}
}
【问题讨论】:
-
不清楚你在问什么。如果练习的目的是显式实现消费者,则该对象必须在 UI 线程之外的线程中执行。就那么简单。对于任何事情,您都不能阻止 UI 线程。但是,UI 线程本身就是一种消费者线程;它将执行您传递给
Control.Invoke()或Control.BeginInvoke()方法的任何委托。这种隐式使用已经存在的 UI 线程使用者实现将适用于大多数实际场景,并且可能适用于您的情况。但是您的问题根本不够清楚,无法知道 -
尝试使用 BlockingCollection,在您的代码中读取时会浪费 CPU。当然,在某些情况下 spinwait 被占用,但不是在这个。
标签: c# multithreading user-interface