03.Programowanie wielowatkowe
Download
Report
Transcript 03.Programowanie wielowatkowe
Jarosław Kuchta
Programowanie
wielowątkowe
Procesy i wątki w systemie
Windows
Windows jest systemem wielowątkowym.
Każdy proces ma przynajmniej jeden wątek, chociaż
może mieć wiele wątków.
Start programu, to start głównego wątku procesu.
Główny wątek może uruchomić inny, poboczny wątek.
Zamknięcie programu, to zamknięcie wszystkich
wątków procesu.
Programowanie wielowątkowe w
języku C
Start programu:
main(), wmain() – w programie konsoli
WinMain(), wWinMain() – w programie okienkowym
Procedura osobnego wątku:
void ThreadProc(void *param)
{
…
_endthread(); // zakończenie wątku
}
Funkcje sterujące wątkami
zadeklarowane w process.h:
_beginthread – rozpoczęcie wątku
_beginthreadex – rozszerzone rozpoczęcie wątku
_endthread – zakończenie wątku
_endthreadex – rozszerzone zakończenie wątku
Przykład – funkcja wątku
void ThreadProc(void *param)
{
// ten wątek po prostu wypisuje parametr
int h=*((int*)param);
printf("%d Thread is Running!\n",h);
_endthread();
}
Przykład – funkcja główna
int main()
{
int n;
int i;
int val = 0;
HANDLE handle;
printf("\t Thread Demo\n");
printf("Enter the number of threads : ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
val = i;
handle = (HANDLE) _beginthread( ThreadProc,0,&val); // utworzenie wątku
WaitForSingleObject(handle,INFINITE); // oczekiwanie na zakończenie
wątku
}
return 0;
}
Programowanie wielowątkowe w
MFC
Hierarchia klas MFC:
CObject – obiekt abstrakcyjny
CCmdTarget – obiekt aktywny
CWinThread – wątek Windows
CWinApp – aplikacja Windows
Aplikacja Windows jest wątkiem!
Dwa rodzaje wątków:
User Interface – wątek oparty o okna
Worker – wątek pracujący w tle
Użyteczne dane
m_nThreadID – identyfikator bieżącego wątku
m_hThread – uchwyt bieżącego wątku
m_bAutoDelete – czy wątek ma się sam usunąć po
zamknięciu?
Funkcje wątkowe
Funkcje globalne:
AfxBeginThread – utworzenie wątku
AfxEndThread – zamknięcie wątku
Metody obiektowe:
CreateThread – utworzenie i wystartowanie wątku
SuspendThread – zawieszenie wątku (inkrementacja licznika
zawieszeń)
ResumeThread – wznowienie wątku (dekrementacja licznika
zawieszeń)
SetThreadPriority – ustawienie priorytetu wątku
GetThreadPriority – pobranie priorytetu wątku
Priorytety wątków
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_IDLE
Przykład z użyciem funkcji Afx
CwinThread *pThread = AfxBeginThread( ThreadFunction, &data);
UINT ThreadFunction(LPVOID param)
{
DWORD result =0 ;
// do somthig
AfxEndThread(exitCode);
return result;
}
Kończenie wątku
funkcja TerminateThread()
funkcja ExitThread()
instrukcja return – zalecana, pozostałe nie czyszczą
stosu.
Programowanie wielowątkowe w
C# (1)
// współdzielona zmienna
private string _threadOutput = "";
// funkcja pierwszego wątku
void DisplayThread1()
{
while (_stopThreads == false)
{
Console.WriteLine("Display Thread 1");
_threadOutput = "Hello Thread1";
Thread.Sleep(1000); // symulacja działania pierwszego wątku
}
}
Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);
Programowanie wielowątkowe w
C# (2)
// funkcja drugiego wątku
void DisplayThread2()
{
while (_stopThreads == false)
{
Console.WriteLine("Display Thread 2");
_threadOutput = "Hello Thread2";
Thread.Sleep(1000); // symulacja działania drugiego wątku
Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);
}
}
Programowanie wielowątkowe w
C# - inicjacja wątków
Class1()
{
// utworzenie dwóch wątków
Thread thread1 = new Thread(new ThreadStart(DisplayThread1));
Thread thread2 = new Thread(new ThreadStart(DisplayThread2));
// wystartowanie wątków
thread1.Start();
thread2.Start();
}
Wynik
Współdzielona zmienna jest asynchronicznie nadpisywana
Synchronizacja przez lock (1)
// współdzielona zmienna
private string _threadOutput = "";
// funkcja pierwszego wątku
void DisplayThread1()
{
while (_stopThreads == false)
{
lock (this) // blokada na własnej instancji
{
Console.WriteLine("Display Thread 1");
_threadOutput = "Hello Thread1";
Thread.Sleep(1000); // symulacja działania pierwszego wątku
Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);
}
}
}
Synchronizacja przez lock (2)
// funkcja drugiego wątku
void DisplayThread2()
{
while (_stopThreads == false)
{
lock(this) // blokada na własnej instancji
{
Console.WriteLine("Display Thread 2");
_threadOutput = "Hello Thread2";
Thread.Sleep(1000); // symulacja działania drugiego wątku
Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);
}
}
}
Wynik (po synchronizacji)
Synchronizacja przez
AutoResetEvent (1)
// zmienne sygnałowe do wzajemnego odblokowywania
AutoResetEvent _blockThread1 = new AutoResetEvent(false);
AutoResetEvent _blockThread2 = new AutoResetEvent(true);
void DisplayThread_1()
{
while (_stopThreads == false)
{
// pierwszy wątek czeka, gdy drugi działa
_blockThread1.WaitOne();
// po wołaniu Set przez drugi wątek, pierwszy kontynuuje działanie
Console.WriteLine("Display Thread 1");
_threadOutput = "Hello Thread 1";
Thread.Sleep(1000); // symulacja działania pierwszego wątku
Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);
// zakończenie działania – odblokowanie drugiego wątku
_blockThread2.Set();
}
}
Synchronizacja przez
AutoResetEvent (2)
void DisplayThread_2()
{
while (_stopThreads == false)
{
// drugi wątek czeka, gdy pierwszy działa
_blockThread2.WaitOne();
// po wołaniu Set przez pierwszy wątek, drugi kontynuuje działanie
Console.WriteLine("Display Thread 2");
_threadOutput = "Hello Thread 2";
Thread.Sleep(1000); // symulacja działania drugiego wątku
Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);
// zakończenie działania – odblokowanie pierwszego wątku
_blockThread1.Set();
}
}