C# COM Cross Thread

2019-04-12 13:32发布

问题:

we're developing a software to control a scientific measuring device. it provides a COM-Interface defines several functions to set measurement parameters and fires an event when it measured data.

in order to test our software, I'm implementing a simulation of that device.

the com-object runs a loop which periodically fires the event. another loop in the client app should now setup up the com-simulator using the given functions.

I created a class for measuring parameters which will be instantiated when setting up a new measurement.

// COM-Object
public class MeasurementParams
{
    public double Param1;
    public double Param2;
}

public class COM_Sim : ICOMDevice
{
    public MeasurementParams newMeasurement;
    IClient client;

    public int NewMeasurement()
    {
        newMeasurment = new MeasurementParam();
    }

    public int SetParam1(double val)
    {
        // why is newMeasurement null when method is called from client loop
        newMeasurement.Param1 = val;
    }

    void loop()
    {
        while(true)
        {
            // fire event
            client.HandleEvent;
        }
    }
}

public class Client : IClient
{
    ICOMDevice server;

    public int HandleEvent()
    {
        // handle this event
        server.NewMeasurement();
        server.SetParam1(0.0);
    }

    void loop()
    {
        while(true)
        {
            // do some stuff...
            server.NewMeasurement();
            server.SetParam1(0.0);
        }
    }
}

both of the loops run in independent threads. when server.NewMeasurement() is called, the object on the server is set to a new instance. but in the next function, the object is null again. do the same when handling the server-event, it works perfectly, because the method runs in the servers thread. how to make it work from client-thread as well.

As the client is meant to be working with the real device, I cannot modify the interfaces given by the manufacturer. also I need to setup measurements independent from the event-handler, which will be fired not regularly.

I assume this problem related to multithreaded-COM behavior but I found nothing on this topic.

回答1:

What is the threading model of the client and the server - STA or MTA? (For reference - STA are single-threaded Com objects meant to allow access to their public methods from only one thread at a time and MTA are multi-threaded objects that allow concurent access to their public methods from multiple threads)

How many instances do you have of each of them and how do you create these? I suspect you want only one, but you are ending up with multiple instead.

How many threads do you have and which method is running on which thread? How do you create those threads and are they initialized to run STA objects or MTA?

Note: .NET is smart enough to detect if both the client and the server are managed and will take COM out of the picture. So, your simulation is running pure managed code. If you want proper test client, you need to write it as a C++ (as I suspect your device controller is unmanaged code).

Reference documentation about COM threading models:

Understanding and Using COM Threading Models
Processes, Threads and Appartments
Introduction to COM Interop



回答2:

In the code you've posted, COM_Sim.client is never assigned. Is there something missing? It's hard to diagnose without seeing how the objects are being assigned.

Additionally: you currently have newMeasurement declared as a public field in COM_Sim, but newMeasurment (spelled differently) inside the method. As written, this code won't compile. It's possible that a similar typo exists in your actual method which is causing you to assign to a different object than the one you thought you created inside NewMeasurement.