powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Можно делать Callback в потоке, о котором .NET ничего не знает?
18 сообщений из 18, страница 1 из 1
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297622
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть DLL на С++, которая создает внутри себя отдельный поток и при некоторых событиях из него вызывает ранее переданную функцию.
исходникиНа c# выглядит так
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
		delegate void CallBack();
		[DllImport("my.dll", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
		static extern Boolean SetFunc(CallBack alert_func);
...
		public Boolean Init() {
			CallBack myCallBack = new CallBack(Alert);
			return SetFunc(myCallBack);
		}
...
		public void Alert() {
			Console.WriteLine("callback ...");
		}


В С++ написано так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
typedef void (*MYCALLBACK) (); 
MYCALLBACK Event;
...
					if(Event != NULL)
					{
						printf("Run callback.\n");
						Event();
					}



Код работает, но периодически происходит вылет с исключением System.AccessViolationException (обращение к несуществующей памяти). Причем никакой почторяемости, может на 2-3 вызов вылететь, может сотню отработать.
Вылет в момент вызова, DLL пишет "Run callback.\n" перед вызовом, а до написания "callback ..." не доходит.

Я так подозреваю что проблема в вызове Alert() в потоке, о котором C# вообще не знает ничего. Хотел спросить: можно так делать?
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297657
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,
имхо нужно застолбить указатель myCallBack через unsafe, уборщик может поменять у нее указатель,
и тогда действительно с++ можем попасть в просак
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297695
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степиимхо нужно застолбить указатель myCallBack через unsafe, уборщик может поменять у нее указатель
Тоже об этом подумал.

Еще появилась мысль что myCallBack может быть вообще удален сборщиком, т.к. нигде больше не упоминается. Переделал его из локальной переменной в свойство класса.
Переделал на такой вариант
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
		unsafe delegate void CallBack();
		[DllImport("my.dll", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
		static extern unsafe Boolean SetFunc(CallBack alert_func);
...
		unsafe CallBack myCallBack;

		public unsafe Boolean Init() { // надо ли тут unsafe?
			myCallBack = new CallBack(Alert);
			return SetFunc(myCallBack);
		}
...
		public unsafe void Alert() { // надо ли тут unsafe?
			Console.WriteLine("callback ...");
		}


Пока не вылетает, мониторю.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297710
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,
да вполне достаточно

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
 private static void Main()
            {
                unsafe
                {
                  // мой код
                  
                }
            }


уборшик не будет анализировать эту область и перемешать в куче ее внутренности внутренности
если хотите оперировать указателями в типе можно так
Код: c#
1.
2.
3.
 public unsafe class CallBack
    {
    }
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297722
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,
Alert наверное лучше статиком сделать, если нет то не использовать его - а инициализировать по месту объявления в параметрах вызова.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39297798
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
После исправлений 19588446 не вылетало больше.

Пришел к выводу что нездоровую хрень я написал. Тут достаточно взять AutoResetEvent в коде DLL его устанавливать, а в C# висеть в ожидании. И никаких колбэков не надо. Переделаю. Эта dll работает в другой проге, на С++, там так проще было реализовать.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298465
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степиимхо нужно застолбить указатель myCallBack через unsafeУказатели "столбятся" через fixed .

Не надо тут ничего "столбить", механизм PInvoke сам что нужно "застолбит" при необходимости. Нужно просто проверить содержимое "колбэка" на потокобезопасность.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298470
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TПосле исправлений 19588446 не вылетало больше.Исправления не внесли никаких изменений. Просто разрешил работу с указателями, которой нет.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298479
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima TПосле исправлений 19588446 не вылетало больше.Исправления не внесли никаких изменений. Просто разрешил работу с указателями, которой нет.
Одно было: переделал myCallBack из локальной переменной в свойство класса.

Помогло или не очень сложно сказать, после исправления не вылетало, 5 часов проработало, а потом переписал: заменил колбэк на AutoResetEvent.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298484
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей Кпропущено...
Исправления не внесли никаких изменений. Просто разрешил работу с указателями, которой нет.
Одно было: переделал myCallBack из локальной переменной в свойство класса.Это ничего не меняет.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298495
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima Tпропущено...

Одно было: переделал myCallBack из локальной переменной в свойство класса.Это ничего не меняет.
Меняет.
Код: c#
1.
2.
3.
4.
		public Boolean Init() {
			CallBack myCallBack = new CallBack(Alert);
			return SetFunc(myCallBack);
		}


После отработки Init() компилятор считает myCallBack больше не нужным и удаляет при сборке мусора, во внутрь SetFunc() компилятор заглянуть не может, т.к. это С++.
У Рихтера есть пример похожей ситуации, когда он создает таймер и больше не упоминает его в коде, и после сборки мусора таймер перестает срабатывать.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298499
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей Кпропущено...
Это ничего не меняет.
Меняет.
Код: c#
1.
2.
3.
4.
		public Boolean Init() {
			CallBack myCallBack = new CallBack(Alert);
			return SetFunc(myCallBack);
		}


После отработки Init() компилятор считает myCallBack больше не нужным и удаляет при сборке мусора, во внутрь SetFunc() компилятор заглянуть не может, т.к. это С++.
У Рихтера есть пример похожей ситуации, когда он создает таймер и больше не упоминает его в коде, и после сборки мусора таймер перестает срабатывать.Сборщик мусора удаляет делегат вместе с скомпилированным телом метода, адрес которого передан в неуправляемый C++ код? Мне кажется, что Рихтер не мог написать такого.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298503
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima Tпропущено...

Меняет.
Код: c#
1.
2.
3.
4.
		public Boolean Init() {
			CallBack myCallBack = new CallBack(Alert);
			return SetFunc(myCallBack);
		}


После отработки Init() компилятор считает myCallBack больше не нужным и удаляет при сборке мусора, во внутрь SetFunc() компилятор заглянуть не может, т.к. это С++.
У Рихтера есть пример похожей ситуации, когда он создает таймер и больше не упоминает его в коде, и после сборки мусора таймер перестает срабатывать.Сборщик мусора удаляет делегат вместе с скомпилированным телом метода, адрес которого передан в неуправляемый C++ код? Мне кажется, что Рихтер не мог написать такого.
Рихтер писал про таймер, а не делегат. В данном случае тоже имеем объект "new CallBack(Alert)". Почему сборщик мусора не должен удалить этот объект?
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298511
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей Кделегат вместе с скомпилированным телом метода, адрес которого передан в неуправляемый C++ код
В С++ попал не адрес тела метода, а какой-то адрес кода-обертки, т.к. C++ понятия не имеет что это метод конкретного объекта, C++ ожидает функцию, т.е. static метод.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298684
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Сдаётся мне, что через PInvoke есть смысл передавать только делегаты, указывающие на статические методы.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298711
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima T,

Сдаётся мне, что через PInvoke есть смысл передавать только делегаты, указывающие на статические методы.
Почему? Просто вынести myCallBack в свойства объекта где он используется и он будет уничтожен одновременно с объектом, дополнительно прописать в Dispose()
Код: c#
1.
SetFunc(null);


чтобы С++ не вызывал несуществующий код.

Меня больше напрягает что поток, в котором вызывается Alert() создан в С++ коде SetFunc(), т.е. .Net ничего не знает про него, возможно .Net пишет какую-то инфу в контекст потока, когда сам создает поток, а тут этого нет, как понадобится эта инфа так все и переглючит.
Поэтому переделал такC#
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
	sealed class MyClass {
		[DllImport("my.dll", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
		static extern Boolean SetFunc(IntPtr handle);

		Thread thread; 
		AutoResetEvent alert;

		public Boolean Init() {
			if(thread == null) {
				alert = new AutoResetEvent(false);
				thread = new Thread(ThreadAlert);
				thread.Start();
			}
			return SetFunc(alert.SafeWaitHandle.DangerousGetHandle());
		}

		public void ThreadAlert() {
			while(alert.WaitOne()) {
				Alert();
			}
		}

		public void Alert() {
			Console.WriteLine("callback ...");
		}



C++
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
HANDLE hAlert = null;

SetFunc(HANDLE h) {
  hAlert = h;
  ... запуск потока использующего hAlert 
}

... где-то в потоке наступило событие
if(hAlert != null) SetEvent(hAlert);


Тут если даже hAlert примет несуществующие значение, то никаких вылетов не будет.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298762
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей КDima T,

Сдаётся мне, что через PInvoke есть смысл передавать только делегаты, указывающие на статические методы.
Почему?Потому что в традиционном неуправляемом коде нет делегатов, есть только указатели на функции, что есть частный случай делегата - делегат статического метода. Не забываем, что делегат - это не просто указатель на функцию, это пара указателей - указатель на функцию и указатель на объект.
...
Рейтинг: 0 / 0
Можно делать Callback в потоке, о котором .NET ничего не знает?
    #39298769
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Хотя нет, Рихтер походу прав . Не знал.

авторAlso, make sure the lifetime of the delegate instance covers the lifetime of the unmanaged code; otherwise, the delegate will not be available after it is garbage-collected.
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Можно делать Callback в потоке, о котором .NET ничего не знает?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]