控制台应用程序中用于STACOM调用的C#计时器
我有一个控制台应用程序,需要启动一个使用COM的方法。程序以[StatThread]开始。当不使用计时器进程时,程序会正确执行,但当使用计时器时,程序显然会阻塞回控制台 我使用过System.Threading.Timer和System.Timers.Timer,但都不起作用。目前,我添加了一个线程来调用使用COM的方法(Transmit())。如果我用Console.Readline清除主线程,程序会在COM对象被阻塞的地方继续运行,但当然程序会关闭,我会丢失所需的计时器功能 在使用控制台应用程序时,我不知道如何设置SynchroningObject以获取ISynchronizeInvoke回调 我不是在寻找多个线程,我只是需要定期调用Transmit方法,并在将结果返回控制台的同时使用COM控制台应用程序中用于STACOM调用的C#计时器,c#,multithreading,timer,com,sta,C#,Multithreading,Timer,Com,Sta,我有一个控制台应用程序,需要启动一个使用COM的方法。程序以[StatThread]开始。当不使用计时器进程时,程序会正确执行,但当使用计时器时,程序显然会阻塞回控制台 我使用过System.Threading.Timer和System.Timers.Timer,但都不起作用。目前,我添加了一个线程来调用使用COM的方法(Transmit())。如果我用Console.Readline清除主线程,程序会在COM对象被阻塞的地方继续运行,但当然程序会关闭,我会丢失所需的计时器功能 在使用控制台应用
class Program
{
private static System.Timers.Timer transTimer;
[STAThread]
static void Main(string[] args)
{
transTimer = new System.Timers.Timer();
transTimer.Enabled = true;
transTimer.Interval = 6000;
transTimer.Elapsed += new System.Timers.ElapsedEventHandler(transTimer_Elapsed);
transTimer.Start();
Console.ReadLine();
transTimer.Dispose();
return;
}
static void transTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (transTimer.Enabled)
{
transTimer.Enabled = false;
Thread thread = new Thread(Transmit);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
thread.Join(); //Wait for the thread to end
transTimer.Enabled = true;
}
}
您违反了一个重要的单线程单元(STA)要求,它必须泵送一个消息循环。如果没有,COM将无法封送从工作线程到创建COM组件的线程的调用。这对于确保以线程安全的方式使用组件是必要的。问题不是你使用了计时器,而是你使用了线程。可观察到的效果是调用死锁 很难在控制台应用程序中获得消息循环。一种解决方法是不在Main()方法中创建COM组件,而是让工作线程创建它,这样就不需要封送处理。通过在循环中调用Sleep()实现周期调用
另一种解决方法是不使用[StatThread]属性。然后COM将自动创建一个STA线程,为COM组件提供一个安全的家。该线程还泵送一个消息循环。现在将对每个调用进行封送处理,如果调用过多,请避免。设置消息泵的.NET方法是Application.Run()。从一个单独的、专用的线程调用它,并使用不在表单中使用的重载。将COM代码保留在该线程上,将控制台代码保留在主线程上,这样控制台就不会阻塞COM逻辑。如果需要计时器与COM逻辑交互,请使用System.Windows.Forms.timer对象,该对象在COM线程上创建并启动。这样,来自它的回调/事件也将在COM线程上运行。@Hans感谢您的反馈。Transmit()方法是COM相关代码所在的位置。它按照您的建议从当前线程中执行。我将尝试删除STAThread,当我不使用计时器时,如果没有它,代码将无法执行。为了我的临时解决办法。我创建了一个名为CmdTimer的独立控制台应用程序,以接受带有参数和间隔的程序路径。它运行计时器,并为每个滴答声派生出一个独立的进程。@Hans,顺便说一句,我不认为您可以在线程启动后更改其ApartmentState,因为线程是在代码执行之前定义的。我不确定COM在启动后如何更改状态。