c# – Accessing variables when calling functions from outside – C #

Question:

Hello, many thanks to everyone who answers!

So I myself got to the point where I can't figure it out, I ask for your help. There is such a code: in a nutshell, the application connects to the exchange program, which, using the RTD interface, gives real-time data on quotes and their updates, the problem is in the update.

From the outside, my UpdateNotify() function of the UpdateNotify() class is RtdUpdate .

  1. How to correctly build the logic for transferring control inside the application, provided that one of the functions is called from the outside?
  2. Where should the code execution be transferred to a new thread under the same condition (calling one of the functions from the outside)?
  3. What should be considered when writing functions that are called from the outside?

There is a code like this:

 <code>
 public partial class Form1 : Form
     {
    //создаем переменную типа RtdClient
    RtdClient rtdClient;
    //создаем переменную типа updateNotification
    RtdUpdate rtdUpdate;
    //конструктор Form1
    public Form1()
    {
        InitializeComponent();
        var tosClassId = new Guid(Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\myapp.COMApp.1\CLSID\", "", null).ToString());
        rtdClient = new RtdClient(tosClassId, this);
        //отправляем ссылку на наш клиент, для обновлений
        rtdUpdate = new RtdUpdate(ref rtdClient);
        //подписываем наш клиент на обновления
        rtdClient.StartListenUpdate(ref rtdUpdate);
    }

    //функция, обновляет значения в массивах, если пришло update
    public void UpdateOnePrice(object _inputSendDataToThread)
    {
        /* тут код который анализирует обновление */
    }

    //класс реализует RtdClient
    public class RtdClient
    {
        Form1 form;
        Type rtd;
        IRtdServer server;


        public RtdClient(Guid _serverId, Form1 _form)
        {
            form = _form;
            rtd = Type.GetTypeFromCLSID(_serverId);
            server = (IRtdServer)Activator.CreateInstance(rtd);
        }

        public void StartListenUpdate(ref RtdUpdate _rtdUpdate)
        {
            server.ServerStart(_rtdUpdate);
        }

        public void updateData()
        {
            try
            {
                var refresh = server.RefreshData(1);

                if (refresh.Length > 0)
                {
                    sendDataToThread send = new sendDataToThread();
                    send.data[0, 0] = refresh[0, 0];
                    send.data[1, 0] = refresh[1, 0];
                    form.UpdateOnePrice(send);
                }
            }
            catch (Exception ex)
            {
                // TODO: Log exception
                MessageBox.Show("error:" + ex);
            }
        }

    }


    public class RtdUpdate : IRTDUpdateEvent
    {
        RtdClient rtdClient = null;
        ThreadManager threadManager;

        public delegate void MethodContainer();

        public RtdUpdate(ref RtdClient _rtdClient)
        {
            rtdClient = _rtdClient;
            threadManager = new ThreadManager();
        }


        public void UpdateNotify()
        {
            //узнаем номер свободного потока
            int numThread = -1;
            while (numThread < 0)
            {
                numThread = threadManager.FreeThreadPlz();
            }
            //запускаем обновление в свободном потоке
            threadManager.threads[numThread] = new Thread(new ThreadStart(rtdClient.updateData));
            threadManager.threads[numThread].Start();
        }
    }

    //класс для того, чтобы описать, то что передаем в новый поток
    public class sendDataToThread
    {
        public object[,] data = new object[2, 1];
    }

    //класс который реализует управление потоками
    public class ThreadManager
    {
        //кол-во разрешенных потоков 
        int threadCount = 10;

        //массив с рабочими потоками
        public Thread[] threads = new Thread[10];

        //какой поток сейчас свободен
        public int FreeThread = 0;

        //конструктор
        public ThreadManager()
        {
            Array.Resize(ref threads, threadCount);
        }

        public int FreeThreadPlz()
        {
            int i = 0;
            for (i = 0; i < threadCount; i++)
            {
                try
                {
                    if (!threads[i].IsAlive)
                    {
                        return i;
                    }
                }
                catch (Exception)
                {
                    return i;
                }
            }
            /*
               LOG TO all BUSY THREAD 
             */

            return -1;
        }
    }
    //ниже описание интерфейсов
    [ComImport, TypeLibType((short)0x1040), Guid("EC0E6191-DB51-11D3-8F3E-00C04F3651B8")]
    public interface IRtdServer
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10)]
        int ServerStart([In, MarshalAs(UnmanagedType.Interface)] IRTDUpdateEvent callback);

        [return: MarshalAs(UnmanagedType.Struct)]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
        object ConnectData([In] int topicId, [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] ref object[] parameters, [In, Out] ref bool newValue);

        [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)]
        object[,] RefreshData([In, Out] ref int topicCount);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(13)]
        void DisconnectData([In] int topicId);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(14)]
        int Heartbeat();

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(15)]
        void ServerTerminate();
    }

    //[ComImport, TypeLibType((short)0x1040), Guid("A43788C1-D91B-11D3-8F39-00C04F3651B8")]
    public interface IRTDUpdateEvent
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10), PreserveSig]
        void UpdateNotify();

        /*
        [DispId(11)]
        int HeartbeatInterval
        {
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
            get;
            [param: In]
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
            set;
        }
        */

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)]
        void Disconnect();
    }
}

Answer:

I would use Publish / Subscribe architecture for communication between threads and Inversion of Control for lifecycle management of threads.

Publish / Subscribe is a kind of data bus within the application through which threads communicate with each other.

In an IoC container, in a separate thread, we create an object that works with a COM object. The object receives a message through the delegate, on its basis it creates its own internal message which it sends to the data bus.

Other threads (interface (viewmodel) or other handlers) pre-subscribe to messages on this data bus, receive messages and use as they see fit.

Easy to learn Publish / Subscribe and Ioc. Nuget: Microsoft.Practices.Prism.PubSubEvents
IoC NuGet container: Unity 4.0.1

Scroll to Top