Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
控制台应用程序中用于STACOM调用的C#计时器_C#_Multithreading_Timer_Com_Sta - Fatal编程技术网

控制台应用程序中用于STACOM调用的C#计时器

控制台应用程序中用于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对象被阻塞的地方继续运行,但当然程序会关闭,我会丢失所需的计时器功能 在使用控制台应用

我有一个控制台应用程序,需要启动一个使用COM的方法。程序以[StatThread]开始。当不使用计时器进程时,程序会正确执行,但当使用计时器时,程序显然会阻塞回控制台

我使用过System.Threading.Timer和System.Timers.Timer,但都不起作用。目前,我添加了一个线程来调用使用COM的方法(Transmit())。如果我用Console.Readline清除主线程,程序会在COM对象被阻塞的地方继续运行,但当然程序会关闭,我会丢失所需的计时器功能

在使用控制台应用程序时,我不知道如何设置SynchroningObject以获取ISynchronizeInvoke回调

我不是在寻找多个线程,我只是需要定期调用Transmit方法,并在将结果返回控制台的同时使用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在启动后如何更改状态。