C++ Wątki, wątek główny

0

Witam,

Już długi czas się meczę z niby błahą rzeczą a mianowicie koniecznie potrzebuje wywołać funkcję z wątku bocznego w wątku głównym. Trochę kodu dla zobrazowania problemu
void Thr:Watek()
{
	Funkcja();
}

void Funkcja()
{
	
}

Dokładnie chodzi o bibliotekę DLL podłączającą się pod aplikacje, Thr:Watek czeka na zmiany środowiskowe a następnie musi wywołać funkcję(w tym przypadku Funkcja()). Dlaczego w wątku głównym? UI Update a tego z innego wątku niż wątek w którym UI zostało stworzone tego nie da się zrobić. Próbowałem tworzyć ukryte okienka a następnie wysyłać do nich SendMessage, ale to przecież działa w innym wątku :(

0

Temat głęboki i szeroki, a hasło to "synchronizacja".

Próbowałem tworzyć ukryte okienka
Brzmi to przerażająco. Do odbierania/wysyłania komunikatów tak na prawdę nie potrzeba żadnych okien. No chyba, że pętla komunikatów jest szczelnie zaszyta we frameworku do GUI, to wtedy przyda się okno typu "mesage-only".

wysyłać do nich SendMessage, ale to przecież działa w innym wątku
Komunikaty można spokojnie przesyłać między wątkami/procesami.

W jakim frameworku robisz GUI? Co do tego wszystkiego ma DLL?

0

Chodzi o to, że nie mam GUI, tworzę wtyczkę, która wysyła dane(autorskim sposobem - ale nie moim) do aplikacji głównej, która to przetwarza i aktualizuje GUI. Wtyczka pracuje w obrębie aplikacji głównej. A cel? Implementacja SkypeKit, który działa w taki sposób, że jest wrapper, który posiada metody, które są wywoływane przez oddzielną aplikację. I właśnie tu jest pies pogrzebany, wtyczka musi wysyłać dane do aplikacji głównej w wątku głównym a SkypeKit "callbackuje"(np. zmiana statusu kogoś na liście) w osobnym wątku. Szukam sposobu żeby właśnie te callbacki mogły wywołać inną funkcję w wątku głównym wtyczki.

0
adf88 napisał(a)

Temat głęboki i szeroki, a hasło to "synchronizacja".

Próbowałem tworzyć ukryte okienka
Brzmi to przerażająco. Do odbierania/wysyłania komunikatów tak na prawdę nie potrzeba żadnych okien. No chyba, że pętla komunikatów jest szczelnie zaszyta we frameworku do GUI, to wtedy przyda się okno typu "mesage-only".

To jest szeroko stosowany wynalazek (okno bez okna tylko do komunikacji). Artefakt Windows-only. Stosowany albo z lenistwa - najłatwiej, albo z braku innych możliwości - nie wiem. W każdym razie to nie jest jakiś wymysł Qzet-a.

0

To w takim razie pomysł z oknem nie jest zły. Musisz je tylko utworzyć w wątku głównym - komunikat dostanie ten wątek, który utworzył okno. Będzie działać pod warunkiem, że aplikacja główna nie przetwarza jakoś dziko komunikatów i ich nie zablokuje.

Alternatywnie, może aplikacja główna udostępnia wtyczce jakieś API które pomoże w problemie? Masz jakąś dokumentację do tego API?

0

Może inaczej, muszę przepchnąć strukturę(a właściwie jej wskaźnik, tak żebym mógł odczytać strukturę w wątku głównym) między wątkami - gdybym wywołał funkcję, która stworzy i wypełni strukturę ale w wątku głównym wtyczki to byłoby to czego szukam.

0

No to tak jak pisałem wyżej. Problem jest w tym, że to aplikacja główna decyduje kiedy wykona jakąś funkcję twojej wtyczki. Ona sama musi wywołać funkcję. Tak więc musisz albo wykorzystać API które udostępnia i wymusić to na niej (może np. udostępnia jakiś timer? tzn. można jej polecić aby np. co sekundę wykonywała jakąś funkcję twojej wtyczki?) albo właśnie użyć komunikatów - wtedy aplikacja wykona zadaną funkcję obsługując komunikaty.

0
JakasStruktura* struktura;

void Funkcja(  )
{
	// ta funkcja jest wykonywana w wątku głównym wtyczki
	// w jaki sposób skorzystać ze `struktura` utworzonej w wątku niżej, koniecznie przez adres
}
DWORD WINAPI ThreadProc(  )
{
	JakasStrukture str;
	str.jakiespole = 1;
	strukrura = &str;
	// ewentualnie
	/*
	JakasStruktura* str = new JakasStruktura;
	str->jakiespole = 1;
	strukura = str;
	*/
}

BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID lpReserved)
{
	CreateThread(0, NULL, ThreadProc, NULL, NULL, NULL);
	Funkcja( );
}

Czyli komunikaty powinny rozwiązać mój problem?

0
Qzet napisał(a)

Czyli komunikaty powinny rozwiązać mój problem?

Ja to rozwiązałem przez synchronizowaną kolejkę - ale to wymaga skanowania po stronie głównego wątku.

A ogólnie to polecam przejrzeć:
http://www.boost.org/doc/libs/1_49_0/doc/html/interprocess.html

0

Czyli komunikaty powinny rozwiązać mój problem?
Tak.

const char MY_CLASS_NAME[] = "Unikatowa nazwa dla mojej klasy handlera komunikatow";
const char MY_MESSAGE_NAME[] = "Unikatowa nazwa dla mojego komunikatu";

const UINT MY_MESSAGE = RegisterWindowMessage(MY_MESSAGE_NAME);

HWND hMessageHandler;

LRESULT CALLBACK MessageHandlerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (uMsg == MY_MESSAGE) {
		JakasStruktura *struktura = (JakasStruktura*)lParam;
		Funkcja(struktura);
		delete struktura;
	}

	/* .. ewentualne  inne komunikaty ... */
}
 
void Funkcja(JakasStruktura* struktura)
{
	/* ... jesteśmy w wątku głównym ... */
	/* ... coś tam sobie robimy ze 'struktura' ... */
}

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	JakasStruktura* str = new JakasStruktura;
	str->jakiespole = 1;
	/* ... reszta pól ... */

	PostMessage(hMessageHandler, MY_MESSAGE, 0, (LPARAM)str);
}

BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID lpReserved)
{
	WNDCLASSEX wndclass;
	ZeroMemory(&wndclass, sizeof(wndclass));
	wndclass.cbSize = sizeof(wndclass);
	wndclass.lpfnWndProc = MessageHandlerProc;
	wndclass.lpszClassName = MY_CLASS_NAME;
	RegisterClassEx(&wndclass);

	hMessageHandler = CreateWindow(MY_CLASS_NAME, "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);

	CreateThread(0, NULL, ThreadProc, NULL, NULL, NULL);
}
vpiotr napisał(a)

ale to wymaga skanowania po stronie głównego wątku.
No właśnie to jest sedno problemu, a nie synchronizacja.

// EDIT
To może nie działać w dwóch sytuacjach:

  • gdy "aplikacja" jakoś dziko obsługuje komunikaty, może zablokować twój komunikat
  • gdy "aplikacja" ładuje wtyczkę z niegłównego wątku

Jeśli problemem będzie jedno lub drugie to można spróbować z Asynchronous Procedure Calls.

1 użytkowników online, w tym zalogowanych: 0, gości: 1