我写了一个做一堆东西的DLL。它所做的一件事是搜索特定消息的大量传入消息,清理消息,并在找到消息时引发事件,并通过EventArgs传递数据。
目前DLL正在运行,但搜索消息的例程正在减慢一切,并使系统响应缓慢,因为有太多数据需要通过。
我想将此搜索移动到它自己的线程,并且一旦找到该消息,它就会在主线程上引发一个事件并将消息数据传递给主线程。我知道如何创建一个线程来完成工作,但我不知道如何让线程在主线程上引发事件并将数据传递给它。有人能告诉我如何做到这一点,还是指出一个例子?
我尝试过创建一个委托并触发一个事件,但是当我尝试传递数据时,我得到一个跨线程异常。
一些可能很重要的细节。很可能根本不会成为GUI,并且可能仍然是控制台应用程序。消息将始终进入,DLL必须不断搜索它们。 DLL正在寻找的消息可能经常每秒发生几次,也可能是消息之间的天数。
更新一个真实的简单项目,说明我想做什么。这段代码很粗糙,因为我把它扔到一起来测试它。
如果您遵循代码,您将看到一切正常,直到CollectData函数中的行:
StatusUpdated(this, null);
被调用。此时,由于UI线程和数据Collection线程,它会导致跨线程异常。我知道我可以通过在UI线程上使用调用来解决这个问题,但如上所述,这很可能不会用于任何类型的GUI(但它应该能够处理它)。因此,需要在BuildResultsManager类中修复跨线程异常,我想在函数BRMgr_StatusUpdated中。如何在不更改MainWindow类中的任何代码的情况下将数据(在本例中为currentVal的值)获取到UI线程。
您可以通过创建包含2个项目的解决方案来运行此操作,前2个文件为1作为dll。第二个作为wpf项目,引用dll,并在表单上放置一个名为status的文本框。
主类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace BuildResultsManager
{
/// <summary>
/// Delegate to notify when data has changed
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
public delegate void StatusUpdatedEventHandler(object sender, EventArgs e);
/// <summary>
/// Connects to the PLC via PVI and reads in all the build results data, conditions it, updates values and reads/store into the database
/// </summary>
public class BuildResultsManager
{
#region events
// Change in The Build Results Manger Status
public event StatusUpdatedEventHandler StatusUpdated;
#endregion
#region Local variables
private Thread collectionThread;
private string statusMessage;
DataCollector dataCollection;
#endregion
#region Properties
/// <summary>
/// Current Status of the Build Results manager
/// </summary>
public String StatusMessage
{
get
{
return statusMessage;
}
private set
{
statusMessage = value;
if (StatusUpdated != null)
StatusUpdated(this, null);
}
}
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public BuildResultsManager()
{
StatusMessage = "successfully initialized";
// start the thread that will collect all the data
dataCollection = new DataCollector();
dataCollection.StatusUpdated += new DCStatusUpdatedEventHandler(BRMgr_StatusUpdated);
collectionThread = new Thread(new ThreadStart(dataCollection.CollectData));
collectionThread.Start();
}
/// <summary>
/// EVent to handle updated status text
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
void BRMgr_StatusUpdated(object sender, EventArgs e)
{
StatusMessage = dataCollection.currentVal.ToString();
}
#endregion
}
}
将完成所有线程工作的类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Threading;
using System.Threading;
namespace BuildResultsManager
{
/// <summary>
/// Delegate to notify when data has changed
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
public delegate void DCStatusUpdatedEventHandler(object sender, EventArgs e);
/// <summary>
/// Handles all of the data collection and conditioning
/// </summary>
class DataCollector
{
#region events
// Change in The Build Results Manger Status
public event DCStatusUpdatedEventHandler StatusUpdated;
#endregion
private const long updateInterval = 1000;
private Stopwatch updateTimer;
public int currentVal;
#region local variables
private bool shouldStop;
#endregion
/// <summary>
/// Default Constructor
/// </summary>
public DataCollector()
{
shouldStop = false;
updateTimer = new Stopwatch();
updateTimer.Start();
}
/// <summary>
/// Main task that listens for new data and collects it when it's available
/// </summary>
public void CollectData()
{
currentVal = 5;
while (!shouldStop && currentVal < 10)
{
if(updateTimer.ElapsedMilliseconds > updateInterval)
{
currentVal++;
if (StatusUpdated != null)
{
StatusUpdated(this, null);
}
//reset the timer
updateTimer.Restart();
}
}
}
/// <summary>
/// Asks the thread to stop
/// </summary>
public void RequestStop()
{
shouldStop = true;
}
}
}
wpf项目背后的代码:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Local variables
private string BRMgrStatus;
private BuildResultsManager.BuildResultsManager BRMgr;
#endregion
public MainWindow()
{
InitializeComponent();
// create an instance of the build manager
BRMgr = new BuildResultsManager.BuildResultsManager();
if(BRMgr != null)
{
status.Text = BRMgr.StatusMessage;
BRMgr.StatusUpdated += new StatusUpdatedEventHandler(BRMgr_StatusUpdated);
}
}
/// <summary>
/// EVent to handle updated status text
/// </summary>
/// <param name="sender">unused</param>
/// <param name="e">unused</param>
void BRMgr_StatusUpdated(object sender, EventArgs e)
{
BuildResultsManager.BuildResultsManager brm;
brm = (BuildResultsManager.BuildResultsManager)sender;
status.Text = brm.StatusMessage;
}
}
答案 0 :(得分:0)
如果您不使用GUI,则无需在同一线程上执行任务,只需使用锁定机制(锁定,互斥等)保护非线程安全资源,以避免并发访问,你很好。