Страницы

Поиск по вопросам

среда, 17 октября 2018 г.

Доступ к переменным при вызове функций извне - C#

Здравствуйте, большое спасибо всем, кто отвечает!
Вот и я сам добрался до момента, когда не могу разобраться, прошу вашей помощи. Имеется такой код: в двух словах, приложение подключается к биржевой программе, которая по средствам RTD interface в реальном времени отдает данные о котировках и их обновлении, проблема как раз в обновлении.
Извне вызывается моя функция UpdateNotify() класса RtdUpdate.
Как правильно построить логику передачи управления внутри приложения, при условии вызова одной из функций извне? В каком месте следует передавать выполнение кода в новый поток при том же условии (вызов одной из функций извне)? Что стоит учесть при написании функций, которые вызываются извне?
Имеется такой код:
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(); } }


Ответ

Я бы использовал Publish/Subscribe архитектуру для сообщения между потоками и Inversion of Control для управления жизненным циклом потоков.
Publish/Subscribe это некая шина данных внутри приложения, через которую потоки общаются между собой.
В IoC контейнере в отдельном потоке создаём объект, который работает с COM объектом. Объект через делегат получает сообщение, на его базе создаёт своё внутренне сообщение которое отдаёт в шину данных.
Другие потоки (интерфейс(viewmodel) или другие обработчики) заранее подписаны на сообщения в этой шине данных, получают сообщения и используют по своему усмотрению.
Не сложные к освоению Publish/Subscribe и Ioc. Nuget:Microsoft.Practices.Prism.PubSubEvents IoC контейнер NuGet:Unity 4.0.1

Комментариев нет:

Отправить комментарий