Wielowątkowość - problem z synchronizacją

Wielowątkowość - problem z synchronizacją
CE
  • Rejestracja:około 4 lata
  • Ostatnio:około 3 lata
  • Postów:48
0

Chciałbym zsynchronizować dwie klasy, które posiadają wskaźnik na ten sam zasób.

  1. Czy mój kod jest poprawny?
  2. Czemu po zmianie join na detach program nie działa?
  3. Czemu po dodaniu mutexa(skomentowany w kodzie) program się nie kompiluje?
Kopiuj
class Foo
{
private:
	bool free = true;
public:
	bool isFree()
	{
		return free;
	}
	void setFree(bool free)
	{
		this->free = free;
	}
};
class Owner
{
private:
	std::shared_ptr<Foo> ptr;
	//std::mutex mtx;
public:
	Owner(std::shared_ptr<Foo> ptr) : ptr(ptr)
	{
	}
	void run()
	{
		while (true)
		{
			//mtx.lock();
			if (ptr->isFree())
			{
				ptr->setFree(false);
				std::cout << "GIT\n";
				Sleep(1000);
				ptr->setFree(true);
			}
			//mtx.unlock();
		}
	}
};
int main()
{
	Foo foo;
	Owner o1 = Owner(std::make_shared<Foo>(foo));
	Owner o2 = Owner(std::make_shared<Foo>(foo));
	std::thread t1(&Owner::run, &o1);
	std::thread t2(&Owner::run, &o2);
	t1.join();
	t2.join();
}

edytowany 3x, ostatnio: Cepo
CE
Dodanie konstruktora kopiującego rozwiązało problem numer 3. Czy z mutexami taki kod jest poprawny?
rajszym
  • Rejestracja:prawie 6 lat
  • Ostatnio:ponad rok
  • Postów:62
3
Cepo napisał(a):
  1. Czy mój kod jest poprawny?
  2. Czemu po zmianie join na detach program nie działa?
  3. Czemu po dodaniu mutexa(skomentowany w kodzie) program się nie kompiluje?

Ad. 1: Nie, zamiast:

Kopiuj
	Foo foo;
 	Owner o1 = Owner(std::make_shared<Foo>(foo));
 	Owner o2 = Owner(std::make_shared<Foo>(foo));

powinno być:

Kopiuj
	auto ptr = std::make_shared<Foo>();
	Owner o1 = Owner(ptr);
	Owner o2 = Owner(ptr);

Ad. 2: Ponieważ program natychmiast opuszcza funkcję main i cały proces łącznie z uruchomionymi zadaniami jest zamykany.

PS.
Zamiast Sleep, używaj std::this_thread::sleep_for

PS.2
W Twoim programie mutex niczego nie synchronizuje.

edytowany 3x, ostatnio: rajszym
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:7 minut
3

Biorąc pod uwagę, że

  • wątki nie współdzielą zasobów, a tego oczekujesz
  • kod wygląda chaotycznie
  • tu nie ma co synchronizować

To powinieneś się skupić na opanowaniu zwykłego programowania, zamiast się brać za programowanie wielowątkowe.
Programowanie wielowątkowe jest

  • trudne
  • łatwo popełnia się błędy, których nie widać (program działa w 1000 przypadków, a w 1001 będzie crashował/dawał złe wyniki).
  • wymaga dużej dyscypliny
  • wymaga dobrej znajomości narzędzi

Ergo, najpierw trzeba opanować podstawy i więcej, zanim zacznie się bawić w wielowątkowość.
Próbując na siłę, w najlepszym razie zniechęcisz się porażkami, w najgorszym dojdziesz coś ci zadziała przez przypadek i dojdziesz do fałszywego przekonanie, że się czegoś nauczyłeś.

Cepo napisał(a):

Chciałbym zsynchronizować dwie klasy, które posiadają wskaźnik na ten sam zasób.

  1. Czy mój kod jest poprawny?

NIE.

  1. Czemu po zmianie join na detach program nie działa?

Zdefiniuj "nie działa"

  1. Czemu po dodaniu mutexa(skomentowany w kodzie) program się nie kompiluje?

Brak inculde? Podaj pełny kod, który się skompiluje bez dopisywania (domyślania się) czegokolwiek.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:mniej niż minuta
  • Lokalizacja:Szczecin
2

Do wypowiedzi Marka dodam jeszcze od siebie: nawet jeśli potrzebujesz wykorzystać wiele wątków, to bardzo rzadko/nigdy nie będziesz używać niskopoziomowych narzędzi takich jak mutex czy thread. Jest pełno bibliotek i frameworków do tego, gdzie jedynie określasz ile ma być wątków wykonania i przekazujesz funkcje/obiekty do threadpoola albo czegoś zbliżonego.

Zgadzam się, że trzeba tu zacząć od podstaw programowania.

Ponadto jeszcze jedna istotna sprawa, która sprawia problemy nowicjuszom: wielowątkowość i współbieżność to różne terminy, tylko częściowo się pokrywające znaczeniowo. Jeśli program ma wykonywać kilka akcji "na raz" - np. czytać z socketa i obsługiwać UI to prawie na pewno użycie wielowątkowości jest tu błędem.


mwl4
to bardzo rzadko/nigdy nie będziesz używać niskopoziomowych narzędzi takich jak mutex. Zobacz co to są na przykład wielowątkowe silniki gier ;-) I jak działają. O ile z użyciem niskopoziomowych threadów się zgodzę, to niestety mechanizmy synchronizacji są potrzebne nawet na wyższych poziomach (niestety).
kq
Synchronizacja jest potrzebna, ale bardzo rzadko musi być jawna, szczególnie tak bardzo niskopoziomowo. Chyba również w silnikach gier, chociaż nigdy nad żadną grą AAA nie pracowałem, więc może o czymś nie wiem.
mwl4
To o czymś nie wiesz. Generalnie temat jest dosyć obszerny. To zależy od przyjętej architektury silnika gry, ale generalnie mając silnik wielowątkowy (oparty na job systemie) nie da się za bardzo uniknąć locków w game systemach (gdzie mówiąc o game systemie mam na myśli ECS). Najczęściej się to dzieje gdzieś przy rejestrowaniu/odrejestrowywaniu komponentów z systemów, ale też w innych miejscach gdzie musi być synchronizacja bo np przetwarzamy komponenty w systemie równolegle i jednocześnie mamy dependencje do systemu. Więcej tutaj https://www.youtube.com/watch?v=JpmK0zu4Mts
kq
Ok, obejrzałem i gość mówi dokładnie to co ja tu napisałem - nie używaj niskopoziomowych narzędzi takich jak mutex/thread, tylko kolejki zadań oparte o threadpoole, promise&future, message passing, etc.
mwl4
To tak jak pisałem - zależy od przyjętej architektury. Fajnie jak można to zrobić bez locków (message passing) ale wtedy najczęściej performance takiego rozwiązania nie jest najlepszy https://youtu.be/JpmK0zu4Mts?t=2072 w tym akurat momencie mówi o tym. Zaznacza, że: "It can perform really well if done well, and really poorly if not". Można też wspomnieć https://www.youtube.com/watch?v=v2Q_zHG3vqg gdzie też unikali locków (ale nie zawsze się dało). Natomiast to jest wiedza już bardzo specjalistyczna.
kq
Ale tu nie chodzi o unikanie locków, tylko o unikanie niskopoziomowych rozwiązań w kodzie! Jak piszę aby nie używać assembly w kodzie to argument, że kompilator i tak zamienia kod na assembly po drodze (so to speak) jest nietrafny - tak samo tutaj. Nowicjusz nigdy nie będzie potrzebował użyć mutexów/threadów poza zajęciami dotyczącymi dokładnie ich.
mwl4
@kq: no właśnie zależy od architektury jaką przyjmiesz w silniku. I nawet nowicjusz może się z tym zetknąć. bardzo rzadko/nigdy nie będziesz używać niskopoziomowych narzędzi takich jak mutex - mutex jest mechanizmem lockowania. Ja pisząc o lockowaniu mam na myśli właśnie użycie mutexa, RWSpinLock, LightMutex, albo innych. Przy message passing możesz ukryć lockowanie w niskopoziomowym kodzie i później tylko go używasz (przygotowujesz message i po prostu wysyłasz. Nie myślisz o żadnym locku, ale on jest gdzieś w mechanizmie). Ale nie zawsze da się tego uniknąć.
enedil
wielowątkowość i współbieżność - może czegoś nie rozumiem, ale dlaczego przeciwstawiasz te dwie kwestie? Pierwsza jest sposobem programowania, druga zaledwie opisuje model wykonawczy programów. W szczególności, zgadza się że jednowątkowe wykonanie współbieżne ma swoje zastosowania (i to sporo), ale chyba dopiero korutyny w C++ są takim powszechnie dostępnym mechanizmem (bez zbyt obskurnych bibliotek zewnętrznych), które pozwalają to osiągnąć. Chyba że masz na myśli mechanizmy typu poll, ale to wówczas nie może się tyczyć niczego innego niż IO (i trzeba również wymyślać
enedil
własne mechanizmy wspomagające, typu trzymanie pipe, tylko po to, żeby można było obudzić z polla, w razie jakiejś ważniejszej sprawy)
kq
Przeciwstawiam, bo dla newbów często wątki są jedynym możliwym rozwiązaniem tego typu problemów
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:7 minut
3

Ja jeszcze dodam, że jeśli naprawdę chcesz efektywnie spożytkować czas, to naucz się pisać testy do kodu.
Używając gtest lub catch2.
Jako początkującemu będzie ci się to wydawać dziwne i mniej "sexy" niż wielowątkowość, ale podstawowe funkcjonalności łatwe w opanowaniu, a jest to umiejętność dużo ważniejsza niż programowanie wielowątkowe.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
_13th_Dragon
Zastąpiłbym "jeśli naprawdę chcesz efektywnie spożytkować czas" na "jeżeli nie masz masochistycznych skłonności"

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.