..::Vlßkna 1 - pracovnφ vlßkna::..

N∞kdy je pot°eba, aby se n∞jakß Φinnost provßd∞la na pozadφ nezßvisle na hlavnφm programu, nap°φklad n∞jak² slo₧it² v²poΦet. Prßv∞ k takovΘmu ·Φelu se hodφ pracovnφ vlßkna. Ka₧d² program mß nejmΘn∞ jedno vlßkno a to hlavnφ vlßkno programu. O to se mßlokdy starßme a v∞tÜina zaΦφnajφcφch programßtor∙ o tom ani nevφ, ale kdy₧ pracujeme s vlßkny tak na to musφme myslet, aby nedoÜlo ke kolizi. Proto₧e, kdy₧ spustφme pracovnφ vlßkno nemßme jedno vlßkno, ale dv∞ vlßkna.

Jak vlßkna vlastn∞ pracujφ? Vlßkna neb∞₧φ souΦasn∞ jak si myslφ n∞kte°φ lidΘ, ale jejich provßd∞nφ se st°φdß. Tj. Chvφli se provßdφ jedno vlßkno, potom se jeho provßd∞nφ pozastavφ a spustφ se provßd∞nφ vlßkna se stejnou nebo vyÜÜφ prioritou a tak dßle. Te∩ by jeÜt∞ cht∞lo vysv∞tlit co jsou to priority vlßken. Priorita urΦuje v jakΘm po°adφ se budou vlßkna provßd∞t. Pamatujte si, ₧e se nikdy nespustφ vlßkno s ni₧Üφ prioritou, kdy₧ Φekß na provßd∞nφ vlßkno s vyÜÜφ prioritou.

JeÜt∞ ne₧ ukß₧i jak se pracovnφ vlßkna vytvß°ejφ musφm vßm °φci n∞co o synchronizaci. Velice Φasto se stßvß, ₧e ve vφce r∙zn²ch vlßknech p°istupujeme ke stejn²m prom∞nn²m. Potom se nßm m∙₧e stßt, ₧e jedno vlßkno zaΦne p°i°azovat hodnotu do jednΘ z t∞chto prom∞nn²ch a p°esn∞ v polovin∞ tΘto operace (dejme tomu ₧e se nastavφ jeden ze dvou byt∙ dvoubytovΘ prom∞nnΘ) se toto vlßkno pozastavφ a spustφ se druhΘ vlßkno, kterΘ Φte (nebo zapisuje) hodnotu tΘ samΘ prom∞nnΘ. Potom v tomto vlßkn∞ zφskßme nesmyslnou hodnotu. Aby se zabrßnilo t∞mto p°φhodßm musφme vlßkna synchronizovat. Pro synchronizaci v rßmci jednΘ aplikace je nejjednoduÜÜφ pou₧φt kritickΘ sekce. Ty d∞lajφ v podstat∞ to, ₧e nedovolφ provßd∞nφ k≤du jinΘho vlßkna chrßn∞nΘho tou samou kritickou sekcφ, dokud se nedokonΦφ provßd∞nφ k≤du v aktußlnφm vlßku chrßn∞nΘho kritickou sekcφ. (To vysv∞tlenφ se mi moc nepovedlo, ale nebojte, vÜe bude jasnΘ z p°φkladu, kter² bude nßsledovat.) JeÜt∞ jedna poznßmka. KritickΘ sekce by se m∞li definovat jako globßlnφ prom∞nnΘ, aby k nim byl snadn² p°φstup odkudkoli.
KritickΘ sekce zapouzd°uje t°φda CCriticalSection. Ta mß dv∞ ΦlenskΘ prom∞nnΘ Lock() - pro oznaΦenφ zaΦßtku chrßn∞nΘ Φßsti k≤du (uzamΦenφ) a Unlock() - pro oznaΦenφ konce chrßn∞nΘ Φßsti k≤du (odemΦenφ).

Existujφ i dalÜφ synchronizaΦnφ objekny jako mutexy, semafory a dalÜφ. Pokud se chcete dozv∞d∞t o synchronizaci vφce, doporuΦuji strßnky www.eternal.cz a to konkrΘtn∞ Φlßnky: Synchronizace pomocφ kritickΘ sekce, Synchronized jako v Java, Synchro objekt Semaphore, Synchro objekt Mutex, Objekt Event, ╚ekßnφ a synchronizace.

A koneΦn∞ k vlastnφm pracovnφm vlßkn∙m. Pracovnφ vlßkno je vlastn∞ reprezentovßno funkcφ, jejφ₧ provßd∞nφ ukonΦφ i provßd∞nφ vlßkna. Tato funkce mß pevn∞ dan² funkΦnφ prototyp a to:

UINT MojeFunkceVlakna( LPVOID pParam );

SpuÜt∞nφ vlßkna se provede pomocφ funkce AfxBeginThread, kterΘ se p°edß jako jeden z parametr∙ ukazatel na void (LPVOID), kter² je p°edßn naÜφ funkci vlßkna. Tato funkce vracφ ukazatel na t°φdu CWinThread, co₧ je t°φda zapouzd°ujφcφ vlßkna. V MFC se pro ka₧dΘ vlßkno vytvo°φ instance tΘto t°φdy, kterß je po skonΦenφ vlßkna automaticky smazßna. Jejφmu smazßnφ m∙₧ete zabrßnit tφm, ₧e nastavφte jejφ Φlenskou prom∞nnou m_bAutoDelete na FALSE. Pomocφ tΘto instance t°φdy m∙₧ete vlßkno ovlßdat z vn∞jÜku vlßkna. Uvnit° vlßkna m∙₧ete tento ukazatel zφskat pomocφ funkce AfxGetThread. Volßnφm ΦlenskΘ funkce m∙₧ete vlßkno pozastavit - SuspendThread, znovu spustit - ResumeThread, zm∞nit prioritu vlßkna - SetThreadPriority a tak dßle.

Nßsleduje okomentovan² p°φklad, ve kterΘm se v hlavnφm vlßkn∞ (vlastnφ aplikace - funkce main) vypisuje na obrazovku hodnota prom∞nnΘ dokud tato prom∞nnß nedosßhne urΦitΘ hodnoty. Hodnota tΘto prom∞nnΘ je zvyÜovßna uvnit° pracovnφho vlßkna. (P°φklad je sice klasickß konzolovß aplikace, ale abyste ji mohli p°elo₧it pot°ebujete mφt zapnutou podporu MFC. To znamenß pou₧φt Φtvrtou mo₧nost AppWizardu pro konzolovΘ aplikace - An aplication that support MFC. To je kv∙li pou₧it²m funkcφm. S vlßkny lze samoz°ejm∞ pracovat i v ΦistΘm C - Φku, ale to se musφ pou₧φt jinΘ funkce.)

// vlakna.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <afxmt.h>// hlaviΦkov² soubor pro synchronizaΦnφ t°φdy

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// The one and only application object

CCriticalSection cs;//deklarace globßlnφ prom∞nnΘ kritickΘ sekce

//Funkce vlßkna

UINT Vlakno(LPVOID pParam)

{

int* pProm = (int*)pParam;    //Konverze parametru funkce na p∙vodnφ typ

int i;                                  //Pomocnß prom∞nnß

for(i=0; i<=10; i++)

{

cs.Lock();                //Vstup (uzamΦenφ) do kritickΘ sekce

/*

    Pokud by se v druhΘm vlßkn∞ v tomto okam₧iku zavolalo cs.Lock(), bude druhΘ vlßkno

    pozastaveno dokud se v tomto vlßkn∞ nezavolß cs.Unlock()

*/

*pProm = i;               //P°i°azenφ hodnoty do prom∞nnΘ p°edanΘ parametrem

cs.Unlock();              //Konec (odemΦenφ) kritickΘ sekce

Sleep(1);                 //Uspßnφ vlßkna na 1 milisekundu

}

return 0;

}


CWinApp theApp;


using namespace std;


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

int nRetCode = 0;


// initialize MFC and print and error on failure

if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))

{

// TODO: change error code to suit your needs

cerr << _T("Fatal Error: MFC initialization failed") << endl;

nRetCode = 1;

}


int pom,x;

x = 0;

// SpuÜt∞nφ vlßkna

CWinThread* pThread = AfxBeginThread(Vlakno,    // ukazatel na funkci vlßkna

&x,                                                                                     // ukazatel na prom∞nnou x - parametr funkce vlßkna

THREAD_PRIORITY_NORMAL);                                  // priorita vlßkna - normßlnφ, stejnß jako hlavnφho vlßkna

while(1)

{

cs.Lock();                 // vstup do kritickΘ sekce

pom = x;                    // p°i°azenφ hodnoty v x do pomocnΘ prom∞nnΘ, aby byla

                                // uzamΦena co nejmenÜφ Φßst k≤du

cs.Unlock();              // konec kritickΘ sekce

printf("%d\n",pom);   // v²pis hodnoty

if (pom==10) break;   // pokud jsme dosßhli Φφsla 10 skonΦφme

}

return nRetCode;

}

 

Pokud chcete o pracovnφch vlßknech v∞d∞t vφc ne₧ jsou tyto minimßlnφ informace, podφvejte se na www.eternal.cz na Φlßnek Multithreading (1. a₧ 6. dφl).