我已经阅读了VB6的线程模型,发现这个link非常有用。
考虑到以下几点......
VB6事件处理程序是否在不同的线程中运行?
不是真的,因为没有单独的线程。 您的代码在单个线程上运行,包含在我上面描述的类似服务的体系结构中。您与之交谈的大部分内容都是其他具有自己公寓的COM对象。所以要来回沟通,当线程互相交谈时,你基本上都在进行RPC调用:你不是直接操纵它们。
除此之外,VB6程序有一个定时器,每4秒钟就会唤醒一次,操纵一些全局变量并重新进入睡眠状态,而主程序正在做它的事情。我无法理解为什么这不会导致碰撞。
“计时器”位于为计时器创建的单独线程上,但是当它调用代码时,保证不会中断任何其他函数,因为函数调用基本上是一次排队一个线程。
...我试图在下面的代码中实现VB6的事件处理行为。
ActionManager.cs
public class ActionManager : IDisposable
{
private readonly BlockingCollection<Action> ActionQueue = new BlockingCollection<Action>(new ConcurrentQueue<Action>());
public ActionManager()
{
}
public void Kickoff()
{
// Start consumer thread
new Thread(ExecuteLoop)
{
IsBackground = true
}.Start();
}
public void AddAction(Action action)
{
ActionQueue.Add(action);
}
private void ExecuteLoop()
{
// Blocks until new actions are available
foreach (var action in ActionQueue.GetConsumingEnumerable())
{
action.Invoke();
}
}
public void Dispose()
{
ActionQueue.CompleteAdding();
ActionQueue.Dispose();
}
}
MainForm.cs
public partial class MainForm : Form
{
public ActionManager actionManager = new ActionManager();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load()
{
// Perform preparatory steps, such as initializing resources,
// configuring settings, etc.
// (Insert preparatory steps here)
// Once preparatory steps are complete, start the ActionManager
actionManager.Kickoff();
}
// Event handler for when the Timer's specified interval has elapsed
private void Timer_Tick(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert timer event steps here)
});
}
// Event handler for when SomeButton is clicked
private void SomeButton_Click(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert button click event steps here)
});
}
}
ActionManager通过一个接一个地执行每个事件来管理事件队列。任何类型的事件,例如鼠标点击,计时器滴答,网络分组到达等,将它们各自的事件处理代码排入事件队列。这样,代码将“在单个线程上”运行,这也将处理不同步的全局变量的问题。
这是正确的实施吗?请分享您的想法!
答案 0 :(得分:4)
如果您要从头开始编写自己的UI框架,那么您所拥有的是自定义消息循环的一个不错的起点。但是你使用的是winforms,你不是从头开始编写自己的UI框架。 Winforms已经拥有自己的消息循环来处理消息,以及一种调度工作在该循环中运行的机制。您无需从头开始创建任何内容。从winforms控件触发的所有事件将已经在UI线程中触发,因此您不需要创建自己的特殊UI线程并管理调度操作。
实际上这样做会导致问题,因为你最终会得到winforms用来管理其UI对象的UI线程,并且你将拥有你正在创建的第二个线程。如果您在该线程中使用过任何UI控件,那么它们会被破坏,因为它们只能在winforms UI线程中使用。
答案 1 :(得分:1)
(我想我首先应该在评论中询问我对遗留应用程序的怀疑是否正确。)
好的,坏消息的时间:你不应该这样做。拜托,拜托,请不要这样做。我告诉你,作为一名开发人员,如果你试图沿着这条路走下去,这将 NOT 结束。
这里发生了什么。您有一个遗留应用程序 - 它可能会对公司非常重要的很多。
但问题是,它可能编写得不是很好,它有点胡思乱想,并且不端口非常适合现代.NET世界。
现在,你可以尝试沿着破坏.NET的方式进入世界的VB6模式......但是你所做的就是把它带到路上。您仍然需要一个写得不好的,糟糕的遗留应用程序,而您仍然需要维护 - 更糟糕的是,您还必须维护.NET-to-VB6-threading-approach方法
我可以保证你正确的方法是重新设计/重新架构它。写出它的作用,问问自己是否有什么可以改进的过程,并在.NET中从头开始编写。有几个原因:
如果它有帮助,让我告诉你一个我曾经做过的旧工作的故事。我和同事都负责将VB6应用程序移植到.NET中。他有一个轮胎检查应用程序,我有一个橡胶混合应用程序。
...我比同事做得更快,我的应用程序更加用户友好,而且维护问题更少了。
管理层可能不喜欢听取您应重写整件事的建议。但是你需要努力争取这个。如果有帮助,请指出大多数软件开发时间不是新编码,而是维护现有软件。可能需要花费更多时间才能重写(即使这不是一个给定的),但从长远来看,它会很快收回成本。