[C++] Synchro wątków


(Kalin 93) #1

Witam

Mój problem polega na synchronizacji wątków, niewiem jak się za to zabrać :wink: Mutexy, semafory - niewiem jak nadać im wartość która mogły by przekazać :wink: Brak synchronizacji objawia się tym że dane nie są wysyłane przez socket :confused:

Proszę, oto kod :

#include 

#include 

#include 

#include 


using namespace std;


DWORD WINAPI Odbieranie (SOCKET &Polaczenia)

{

	cout << "Uruchomiono watek Wysylajacy\n";

	string sPolecenie;

	if (Polaczenie == INVALID_SOCKET) cout << "Blad!!!";

	for (;;)

	{

		cin >> sPolecenie;

		if (send (Polaczenie,sPolecenie.c_str(),sPolecenie.length()+1,NULL) == 0) cout << "Blad wyslania !";

		cout << "Wyslano!";

	}

}


int main ()

{

	WORD wersja = MAKEWORD (2,0);

	WSADATA wsaData;

	if(!WSAStartup(wersja, &wsaData))

	{

		cout << "WSA uruchomione poprawnie!\n";

	}

	if (LOBYTE (wsaData.wVersion) != 2 && HIBYTE (wsaData.wVersion != 0)) cout << "Uruchomiono niepoprawna wersje WSA !";

	SOCKET Polaczenie;

	Polaczenie = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (Polaczenie == INVALID_SOCKET)

	{

		cout << "Nie mozna utworzyc socketa!";

		WSACleanup ();

	}

	hostent *host=0;

	string sAdresSerwera = "krakow.irc.pl";

	sockaddr_in server;

	int nPort = 6667;

	memset (&server,0,sizeof (server));

	server.sin_family = AF_INET;

	server.sin_port = htons ((u_short)nPort);

	server.sin_addr.s_addr = inet_addr (sAdresSerwera.c_str());

	if (server.sin_addr.s_addr == INADDR_NONE)

	{

		host = gethostbyname (sAdresSerwera.c_str());

		if (host == NULL) cout << "Nie moge skonwertowac adresu!\n";

		CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length);


	}

	if (!connect (Polaczenie,(sockaddr*)&server,sizeof (server)))

	{

		cout << "Polaczono !\n";

	};

	DWORD ThreadID;

	HANDLE hOdbieranie = CreateThread (0,0,(LPTHREAD_START_ROUTINE)Odbieranie,&Polaczenie ,NULL,&ThreadID);

	char cBufor [5001];

	for (;;)

	{

		memset (cBufor,0,sizeof (cBufor));

		recv (Polaczenie,cBufor,5000,NULL);

		cout << cBufor;

	}

	_getch();

}

(Fiołek) #2

Mutexy i semafory działają troszkę inaczej :wink: Tworzysz dwie zmienne, jedną z wartością, drugą z semaforem. Gdy chcesz pobrać/zapisać blokujesz semafor WaitForSingleObject i robisz co potrzeba, potem zwalniasz semafor. I to by było na tyle :wink:


(Kalin 93) #3

Czyli tworzę sobie semafor według MSDN ma to wyglądać tak :

HANDLE WINAPI CreateSemaphore(

  __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

  __in LONG lInitialCount,

  __in LONG lMaximumCount,

  __in_opt LPCTSTR lpName

);

I w parametr lpName mam podać obiekt to zsynchronizowania tak ?


(Fiołek) #4

Nie, lpName to nazwa semafora(więcej info na MSDN). Pokaże na kodzie(pseudokod):

int g_Val;

HANDLE g_ValSemaphore;


void ThreadFunc() //Funkcja wątku

{

   while(true)

   {

      if(WaitForSingleObject(g_ValSemaphore, INFINITE) == WAIT_OBJECT_0)) //Jeśli mamy dostęp

      {

         //Robimy coś z g_Val.

         ReleaseSemaphore(g_ValSemaphore);

      }

   }

}


int main()

{

   g_Val = 0;

   g_ValSemaphore = CreateSemaphore(...); //Odpowiednie parametry.

   RunThread(ThreadFunc); //Uruchamiamy wątek

   while(true)

   {

      if(WaitForSingleObject(g_ValSemaphore, INFINITE) == WAIT_OBJECT_0)) //Jeśli mamy dostęp

      {

         ++g_Val;

         ReleaseSemaphore(g_ValSemaphore);

      }

   }

}

Rozumiesz już?

EDIT: Tutaj jest tutorial obrazujący jak się używa semafora. :wink:


(Kalin 93) #5

Tak :wink: Tylko nie mogę pojąć jaki fragment kodu jest odpowiedzialny za synchro .

Byłbym wdzięczny gdybyś powiedział jaki fragment kodu za to odpowiada .


(Fiołek) #6

Aktualizuje g_Val w pętli w mainie blokując dostęp innym wątkom. To jest cała synchronizacja. Jak potrzebujesz bardziej rozwiniętej(nie przeglądałem kodu) to musisz sobie ją zapisać. Ja tylko napisałem jak dostać się do obiektu z kilku wątków, ale tak, żeby w tym samym czasie dwa wątki go nie aktualizowały(żeby dostęp do obiektu był zsynchronizowany).


(Kalin 93) #7

Dobra :wink: Rozumiem już wszystko :wink:

A teraz mam jeszcze problem żeby dostęp do socketa miał inny wątek niż tylko main. Wiesz może jak to rozwiązać ? Dodam że jeśli wrzuciłem go jako zmienną globalną to nie łączył się w ogole, a jeśli utworzyłem go w globalu a nadałem wartość w funkcji main to łączył się ale nic nie dało.


(Fiołek) #8

Nie jestem pewien, ale socket jest chyba przypisany do wątku.


(Kalin 93) #9

Chyba jednak nie :wink: Bo, na jednym sockecie można podłączyć kilka klientów, a wiec jakoś musi się dać to udostępnić tylko nie wiem jak :wink: Od kilku godzin szukam w google, MSDN ale nie potrafie znaleźć :confused: