Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
Emile
/
PATRICE
/
Prog
:
multithread2.mspx.htm
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<html dir="ltr"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><meta name="MS.LOCALE" content="nl-be"><meta name="ms.locale" content="nl-be"><meta name="title" content="Microsoft Belgi� & Luxemburg - MSDN - Multi-threading et synchronisation: seconde partie"><title>Microsoft Belgi� & Luxemburg - MSDN - Multi-threading et synchronisation: seconde partie</title><meta name="description" content="Multi-threading et synchronisation: seconde partie ; Laurent introduit la notion de thread et couvre les aspects de cr�ation et de destruction d'un thread. (Engels)"><meta name="keywords" content="Multi-threading et synchronisation, Windows CE Embedded 3.0 et 4.x, Embedded Visual C++ 3.0"><meta name="last-updated" content="May 16, 2003"><style> .text0 {font: 70% Verdana; font-weight: bold; line-height: 140%} .text1 {font: 90% Verdana; line-height: 140%; font-weight: bold} .anchor1 {font: 70% Verdana; color: #6699CC} .text2 {font: 70% Verdana; padding-bottom: 10px; line-height: 140%} .text2_no_bottom {font: 10px Verdana;line-height: 140%} .text2_blue {font: 10px Verdana; padding-bottom: 10px; line-height: 140%;color: #003399} .text3 {font: 70% Verdana; font-weight: bold; color: white} .text4 {font: 70% Verdana; color: black} .text5 {font: 10px Verdana; color: white} .textdate {font: 80% Verdana; color: #999999} .footer {font: 70% Verdana; color: black; font-style: italic} .textcode {font: 90% Courier New; color: black} .code {font-size: 120%; background-color: #cccccc; color: black; font-family: Courier New, Courier; margin-top: 5px; padding: 1px;} .inlineCode {font-size: 100%; background-color: #f1f1f1; color: black; font-family: Courier New, Courier; margin-top: 5px; padding-top: -5px; } .summery {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:80%; color:#003399;} H1 {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:120%;color:#003399;} H2 {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:100%;color:#003399;} H3 {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:70%; font-weight: bold; color:#003399;} .subtitle {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:70%; font-weight: bold; color:#003399;} A.moreinfo { font-weight: normal; font-size: 11px; } A.moreinfo:hover { font-weight: normal; font-size: 11px; } A.moreinfo:visited { font-weight: normal; font-size: 11px; color: #800080; } UL { font-weight: normal; font-size: 11px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; } TABLE.DATA { font-weight: normal; font-size: 11px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; border-collapse:collapse; border-left:solid 1 #CCCCCC; border-top:solid 1 #CCCCCC; } TH.DATA { border-right:solid 1 #CCCCCC; border-bottom:solid 1 #CCCCCC; background-color:#EEEEEE; } TD.DATA { font:normal; border-right:solid 1 #CCCCCC; border-bottom:solid 1 #CCCCCC; background-color:#FFFFFFF; } </style><script language="JavaScript"> function popup(URLName) { window.open("http://www.subscriptions.be/netmag/" + URLName + ".asp",URLName,"width=500,height=560,scrollbars=yes,toolbar=no,resizable=no,menubar=no,location=no"); } </script> <script type="text/javascript" language="Javascript" src="multithread2.mspx_fichiers/menujs"></script> <link type="text/css" rel="Stylesheet" href="multithread2.mspx_fichiers/css_002.css"> <link rel="stylesheet" type="text/css" href="multithread2.mspx_fichiers/css.css"><script language="JavaScript">var doImage=doImage;var TType=TType; function mhHover(tbl,idx,cls){var t,d;if(document.getElementById)t=document.getElementById(tbl);else t=document.all(tbl);if(t==null)return;if(t.getElementsByTagName)d=t.getElementsByTagName("TD");else d=t.all.tags("TD");if(d==null)return;if(d.length<=idx)return;d[idx].className=cls;} function footerjs(doc){if(doImage==null){var tt=TType==null?"PV":TType;doc.write('<layer visibility="hide"><div style="display:none"><img src="http://c.microsoft.com/trans_pixel.asp?source=www&TYPE=' + tt + '&p=belux_nl_msdn_community_columns_ldoc&URI=%2fbelux%2fnl%2fmsdn%2fcommunity%2fcolumns%2fldoc%2fmultithread2.mspx&GUID=1F4FC18C-F71E-47FB-8FC9-612F8EE59C61&r=http%3a%2f%2fwww.google.fr%2fsearch%3fhl%3dfr%26q%3dWaitForSingleObject%2b%2bC%2bexemple%26btnG%3dRechercher%26meta%3dlr%3dlang_fr&lc=nl-be" width=0 height=0 hspace=0 vspace=0 border=0 alt=""/></div></layer>');}}</script><script language="JavaScript" src="multithread2.mspx_fichiers/broker.js"></script><script language="Javascript"> if (self.name == "MNPMainFrame") top.location.href = self.location.href; </script><meta name="save" content="favorite"></head> <body topmargin="0" leftmargin="0" bgcolor="#ffffff" marginheight="0" marginwidth="0"><!--NOINDEX_START--><a name="top"></a><div id="msviMasthead"><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td width="100%"><table border="0" cellpadding="0" cellspacing="0" height="22" width="100%"><tbody><tr><td id="msviRegionIdGraphic" bgcolor="#ffffff"><img src="multithread2.mspx_fichiers/text_002.jpg" alt="Belgi� en Luxemburg" title="" border="0" height="22"></td><td bgcolor="#3568cc" width="100%"><img src="multithread2.mspx_fichiers/gradient.jpg" alt="*" title="" height="22" width="250"></td></tr></tbody></table></td><td id="msviGlobalToolbar" align="left" bgcolor="#3568cc" dir="ltr" height="22" nowrap="nowrap"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gt0" onmouseover="mhHover('msviGlobalToolbar', 0, 'gt1')" onmouseout="mhHover('msviGlobalToolbar', 0, 'gt0')" nowrap="nowrap"><a href="http://www.microsoft.com/belux/">Home Microsoft Belux</a></td><td class="gtsep">|</td><td class="gt0" onmouseover="mhHover('msviGlobalToolbar', 2, 'gt1')" onmouseout="mhHover('msviGlobalToolbar', 2, 'gt0')" nowrap="nowrap"><a href="http://www.microsoft.com/library/toolbar/3.0/sitemap/nl-be.mspx">Siteplan</a></td></tr></tbody></table></td></tr><tr valign="top"><td width="100%"><table style="" border="0" cellpadding="0" cellspacing="0" height="42" width="100%"><tbody><tr valign="top"><td id="msviBrandBanner" bgcolor="#ffffff"><a href="http://www.microsoft.com/belux/"><img src="multithread2.mspx_fichiers/msdn_masthead_ltr.gif" alt="Microsoft" title="" border="0" height="42" width="225"></a></td><td bgcolor="#6799ff" width="100%"><img src="multithread2.mspx_fichiers/gradient_002.jpg" alt="*" title="" height="42" width="250"></td></tr></tbody></table></td><td id="msviGlobalSearch" bgcolor="#6799ff">Zoeken op Microsoft.com :<br><form id="msviSearchForm" action="/library/toolbar/3.0/search.aspx"><input name="View" value="nl-be" type="hidden"><input name="charset" value="iso-8859-1" type="hidden"><nobr><div style="height: 18px;"><input name="qu" id="msviSearchBox" maxlength="255"><input id="msviGoButton" value="Go" type="submit"></div></nobr></form></td></tr></tbody></table><div id="msviLocalToolbar"><table border="0" cellpadding="0" cellspacing="0" height="19" width="100%"><tbody><tr><td id="msviHomePageLink" nowrap="nowrap"><a href="http://www.microsoft.com/belux/NL/msdn/default.mspx">MSDN Belux Home</a></td><td><span class="ltsep">|</span></td><td class="lt0" onmouseover="mhHover('msviLocalToolbar', 2, 'lt1')" onmouseout="mhHover('msviLocalToolbar', 2, 'lt0')" nowrap="nowrap"><a href="http://www.microsoft.com/belux/fr/msdn/default.mspx">Site Francophone</a></td><td><span class="ltsep">|</span></td><td class="lt0" onmouseover="mhHover('msviLocalToolbar', 4, 'lt1')" onmouseout="mhHover('msviLocalToolbar', 4, 'lt0')" nowrap="nowrap"><a href="http://www.microsoft.com/belux/msnl.asp">Belux Home</a></td><td><span class="ltsep">|</span></td><td class="lt0" onmouseover="mhHover('msviLocalToolbar', 6, 'lt1')" onmouseout="mhHover('msviLocalToolbar', 6, 'lt0')" nowrap="nowrap"><a href="http://www.microsoft.com/belux/nl/msdn/community/newsletter.mspx">Newsletter for developers</a></td><td width="100%"></td></tr></tbody></table></div></div><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr valign="top"><td style="" height="100%" width="181"><div id="mnpMenuTop" class="mnpMenuTop" style="width: 181px;" url="/belux/nl/msdn/community/columns/ldoc/multithread2.mspx" parent="/belux/nl/msdn/community/articles.mspx" dir="ltr"><div class="mnpInherit"><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;" menu="m8652ac28081d418499ecc6d7a88eba5c"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/NL/msdn/devtools/default.mspx">Development tools</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;" menu="m4f919bfd471f4c769f1d2ff78c6f21d2"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/events/overview.mspx">Events & training</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;" menu="m3b5901996d5a45d0badd2efaf75c1d2f"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/community/default.mspx">Community</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;" menu="mb5c26356fcaf4e299de9da3590401dae"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://msdn.microsoft.com/">MSDN US</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;" menu="m25b49eb6705042c99299160ae49b01e8"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/support/default.mspx">Support</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/rssfeed.mspx">RSS Feeds</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/newsarch.mspx">All news</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/msdn/sitemap.mspx">Site map</a></div><div class="mnpMenuBorder" style="width: 180px;"></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/belux/nl/technet/">IT Professional</a></div><div class="mnpMenuRow" style="border-color: rgb(241, 241, 241); background: rgb(241, 241, 241) none repeat scroll 0%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial; width: 153px;"><img alt="*" title="" class="mnpMenuArrow" src="multithread2.mspx_fichiers/arrowLTR.gif" style="left: 166px; visibility: hidden;" border="0" height="7" width="4"><a href="http://www.microsoft.com/isapi/gomsdn.asp?TARGET=/architecture/">Architect</a></div><div class="mnpMenuBorder" style="width: 180px; margin-bottom: 0px;"></div></div></div><div class="mnpAds" style="border-style: solid; border-color: rgb(153, 153, 153); border-width: 0px 1px 0px 0px; background: rgb(241, 241, 241) none repeat scroll 0%; width: 181px; height: 100%; padding-bottom: 20px; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial;"><center></center></div></td><td dir="ltr" width="100%"><!--NOINDEX_STOP--> <table cellpadding="15" cellspacing="0" width="100%"><tbody><tr valign="top"><td width="100%"><div style="margin-left: 0px; margin-bottom: 20px;"><h1>Multi-threading et synchronisation: seconde partie</h1><div class="footer"> Laurent Docquir<br> Ezos s.a. </div><br><span class="summery"><b>S'applique �:</b><br><ul><li>Windows CE Embedded 3.0 et 4.x</li><li>Embedded Visual C++ 3.0</li></ul></span><div class="summery"><b>R�sum�: </b>Laurent discute des probl�mes li�s � l'ex�cution concurrente de plusieurs threads au sein d'une m�me application. </div><br><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Introduction"></a><h2>Introduction</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Dans <a target="" href="http://www.microsoft.com/belux/nl/msdn/community/columns/ldoc/multithread1.mspx">la premi�re partie</a> de l'article, nous avons d�couvert la notion de thread et surtout nous avons fait le tour des fonctions Win32 qui permettent de les g�rer. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Dans cette seconde partie, nous allons discuter des probl�mes li�s � l'ex�cution concurrente de plusieurs threads au sein d'une m�me application. En effet ce n'est pas le tout de cr�er 50 threads, encore faut il pouvoir avoir une emprise sur la mani�re, l'ordre dans lequel ils s'ex�cutent. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici la liste des points que nous allons aborder dans cet article : <ul><li><b></b> L'acc�s simultan� � une ressource globale unique </li><li><b></b> L'acc�s simultan� � une ressource globale multiple </li><li><b></b> Un thread commence son ex�cution quand un pr�c�dent se termine </li><li><b></b> Un thread commence son ex�cution sur base d'un �v�nement ext�rieur </li></ul><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="L'acc�s simultan� � une ressource globale unique"></a><h2>L'acc�s simultan� � une ressource globale unique</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Au sein d'une application, tous les threads utilisent le m�me espace d'adressage virtuel. En d'autres termes, et pour �tre clair, deux threads provenant d'une m�me application peuvent partager une ou plusieurs zones m�moires. Pratiquement une telle zone m�moire est : <ul><li><b></b> Une variable globale de l'application </li><li><b></b> Un buffer allou� dynamiquement par un appel � malloc, new, HeapAlloc ou autre fonction d'allocation de m�moire </li></ul> Lorsque deux threads acc�dent une m�me zone m�moire, il est possible qu'ils essaient de changer ou de lire sa valeur en m�me temps. Trois cas peuvent se poser : <ol><li><b></b> Deux lecteurs : les deux threads acc�dent la variable en lecture. Ce cas n'est pas tr�s courant, n�anmoins il ne pose pas de probl�mes particuliers. </li><li><b></b> Un lecteur, un �crivain : un thread est ma�tre de la valeur de la zone m�moire, l'autre ne fait que lire son contenu. </li><li><b></b> Deux �crivains : les deux threads sont susceptibles de modifier la valeur de la zone m�moire. </li></ol><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Cas du lecteur et de l'�crivain.</b><br> Pour comprendre la situation, consid�rez le code suivant : <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> DWORD g_dwTemperature;<br><br> DWORD WINAPI Reader(LPVOID p)<br> {<br> for (;;)<br> {<br> if (g_dwTemperature <= 70)<br> {<br> // L'eau n'est pas trop chaude<br> LaverLinge(); // dur�e : 30 min<br> }<br> }<br> }<br><br> DWORD WINAPI Writer(LPVOID p)<br> {<br> for (;;)<br> {<br> // Toute les minutes la temp�rature de l'eau <br> augmemente de 1 degr�.<br><br> g_dwTemperature++ ;<br> Sleep(60000) ;<br> }<br> } </font></td></tr></tbody></table><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Le probl�me est le suivant : imaginons que au moment ou le thread 1 (Reader) est sur le point de commencer un lavage, il d�tecte une temp�rature de 60�. Cette derni�re est acceptable puisque inf�rieure � 70�, le thread 1 lance donc la proc�dure de lavage. Cette proc�dure dure 30 minutes. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Pendant ces 30 minutes, le thread 2 ne perd pas son temps et continue � chauffer l'eau. Apr�s exactement 11 minutes, la temp�rature aura atteint 71� ce qui n'est plus une valeur acceptable pour le linge. Malheureusement la fonction LaverLinge va encore s'ex�cuter pendant 19 minutes. Pas besoin de vous faire un dessin pour vous faire comprendre que le linge ne pourra plus �tre mis que par poup�e barbie ;-) <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Mon exemple est un peu tir� par les cheveux je l'admet mais il illustre bien le probl�me. Ce probl�me arrive g�n�ralement sur des intervalles de temps beaucoup plus petit que la deemi-heure. Le principe est que entre le moment ou un thread lit la valeur et va l'utiliser, un autre peut l'avoir chang�e. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Pour solutionner ce probl�me, il suffit de se dire que lorsque un lavage est en cours, on se limite � garder la temp�rature stationnaire. Comment peut-on s'y prendre ? <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>La technique du jeton</b><br> C'est tr�s simple. Nous allons cr�er un jeton et d�cr�ter que pour modifier la temp�rature de l'eau de 1�, il faut imp�rativement s'approprier le jeton. Evidemment l'int�r�t du jeton est que seul un thread peut en avoir la propri�t� � un moment donn�. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Pour obtenir le jeton, le thread doit en faire la demande. Si le jeton est disponible (c�d qu'il n'est pris par aucun autre thread), il lui est attribu�. Si le jeton n'est pas disponible, le thread qui a fait la demande est mis en veille par le syst�me jusqu'� ce que le soit � nouveau disponible. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Revenons � notre exemple ! Si le thread 2 effectue un demande du jeton avant d'augmenter la temp�rature, on peut facilement le contr�ler. En effet il suffit au thread 1 de prendre le jeton avant de commencer � laver le linge et de le rendre � la fin de la lessive. Ainsi le thread 2 ne pourra jamais obtenir le jeton durant la p�riode de lessivage. Probl�me r�solu. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>C'est bien beau tout cela mais comment j'impl�mente mon jeton ?</b><br> Le syst�me Win32 propose deux impl�mentations d'un jeton simple : le mutex et la section critique. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Les op�rations que nous voulons ex�cuter avec un jeton sont les suivantes : cr�er, obtenir, rendre et d�truire. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><i>Impl�mentation sous forme de mutex</i><br> Le tableau ci-dessous donne les fonctions Win32 associ�es au mutex pour les 4 op�rations : <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><div align="center"><center><table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="90%"><tbody><tr><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Op�ration</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Fonction Win32</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Remarques</font></b></td></tr><tr><td class="text4" valign="top"> Cr�er </td><td class="text4" valign="top"><b>CreateMutex</b></td><td class="text4" valign="top"><ul><li><b></b> On peut obtenir le jeton d�s sa cr�ation </li><li><b></b> On peut nommer le jeton </li></ul></td></tr><tr><td class="text4" valign="top"> Obtenir </td><td class="text4" valign="top"> Wait functions : <ul><li><b></b><b>WaitForSingleObject</b></li><li><b></b> ... </li></ul></td><td class="text4" valign="top"><ul><li><b></b> Si le jeton n'est pas dispo, les fonctions wait bloquent le thread appellant jusqu'� ce que le jeton soit libre ou qu'il soit d�truit ou encore qu'un certain d�lai se soit �coul�. </li></ul></td></tr><tr><td class="text4" valign="top"> Rendre </td><td class="text4" valign="top"><b>ReleaseMutex</b></td><td class="text4" valign="top"> </td></tr><tr><td class="text4" valign="top"> D�truire </td><td class="text4" valign="top"><b>CloseHandle</b></td><td class="text4" valign="top"> </td></tr></tbody></table></center></div><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Et voici donc notre exemple modifi� en cons�quence : <table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> DWORD g_dwTemperature;<br> HANDLE g_hMutex<br><br> g_hMutex = CreateMutex(NULL,FALSE,NULL);<br> ...<br><br> DWORD WINAPI Reader(LPVOID p)<br> {<br> for (;;)<br> {<br> __try<br> {<br> // Obtenir le jeton<br> WaitForSingleObject(g_hMutex,INFINITE) ;<br> if (g_dwTemperature <= 70)<br> {<br> // L'eau n'est pas trop chaude<br> LaverLinge(); // dur�e : 30 min<br> }<br> }<br> __finally<br> {<br> // Rendre le jeton apr�s que la lessive soit termin�e<br> ReleaseMutex(g_hMutex);<br> }<br> }<br> }<br><br> DWORD WINAPI Writer(LPVOID p)<br> {<br> for (;;)<br> {<br> // Toute les minutes la temp�rature de l'eau <br> augmemente de 1 degr�.<br> __try<br> { <br> Sleep(60000) ;<br> WaitForSingleObject(g_hMutex,INFINITE) ; <br> g_dwTemperature++ ;<br> }<br> __finally<br> {<br> ReleaseMutex(g_hMutex);<br> }<br><br> }<br> }<br></font></td></tr></tbody></table><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Important :</b><br> Dans l'exemple ci-dessus, outre le fait que j'ai introduit la notion de jeton, j'ai aussi mis en place une gestion d'exception au moyen du __try __finally. Ceci est primordial : si toutefois une exception est g�n�r� dans la fonction LaverLinge, je rendrai quand m�me le jeton proprement. Dans le cas contraire une exception non g�r�e dans la fonction LaverLinge fera exploser le thread 1 et celui-ci n'aura jamais l'occasion de rendre le jeton. Ce qui aura pour effet que le thread 2 sera bloqu� � jamais. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><i>Impl�mentation sous forme de section critique.</i><br> Contrairement au mutex qui est un objet du noyau, la section critique est une simple structure en m�moire. La finalit� de la section critique est la m�me que celle du mutex. Le seul int�r�t d'une section critique est qu'elle ne n�cessite aucun service du noyau, elle consomme moins de ressources syst�mes et est donc plus performante. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Elle a cependant une limitation: elle ne peut servir que � synchroniser des threads qui font partie d'un m�me processus. Un mutex ,par contre, peut se voir attribuer un nom lors de l'appel Win32 <b>CreateMutex</b>. Dans ce cas, un thread r�sidant dans un autre processus peut obtenir un handle sur ce m�me mutex en appellant <b>CreateMutex</b> ou <b>OpenMutex</b> avec le m�me nom. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici le tableau des fonctions li�es aux sections critiques : <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><div align="center"><center><table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="90%"><tbody><tr><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Op�ration</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Fonction Win32</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Remarques</font></b></td></tr><tr><td class="text4" valign="top"> Cr�er </td><td class="text4" valign="top"><b>D�clarer une structure CRITICAL_SECTION</b></td><td class="text4" valign="top"><ul><li><b></b> Une CS est donc une simple variable </li><li><b></b> Cette var doit �tre initialis�e par un appel � <b>InitializeCriticalSection</b></li></ul></td></tr><tr><td class="text4" valign="top"> Obtenir </td><td class="text4" valign="top"><b>EnterCriticalSection</b> ou <b>TryEnterCriticalSection</b></td><td class="text4" valign="top"> </td></tr><tr><td class="text4" valign="top"> Rendre </td><td class="text4" valign="top"><b>LeaveCriticalSection</b></td><td class="text4" valign="top"> </td></tr><tr><td class="text4" valign="top"> D�truire </td><td class="text4" valign="top"><b>DeleteCriticalSection</b></td><td class="text4" valign="top"> </td></tr></tbody></table></center></div><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Et revoici notre exemple revu et corrig� � la sauce � section critique � <table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> DWORD g_dwTemperature;<br> CRITICAL_SECTION g_cs;<br><br> // Ne pas oublier d'initialiser la structure<br> InitializeCriticalSection(&g_cs);<br> ...<br><br> DWORD WINAPI Reader(LPVOID p)<br> {<br> for (;;)<br> {<br> __try<br> {<br> EnterCriticalSection(&g_cs);<br> if (g_dwTemperature <= 70)<br> {<br> // L'eau n'est pas trop chaude<br> LaverLinge(); // dur�e : 30 min<br> }<br> }<br> __finally<br> {<br> LeaveCriticalSection(&g_cs);<br> }<br> }<br> }<br><br> DWORD WINAPI Writer(LPVOID p)<br> {<br> for (;;)<br> {<br> // Toute les minutes la temp�rature de l'eau <br> augmemente de 1 degr�.<br> __try<br> { <br> EnterCriticalSection(&g_cs); <br> g_dwTemperature++ ;<br> Sleep(60000) ;<br> }<br> __finally<br> {<br> LeaveCriticalSection(&g_cs);<br> }<br><br> }<br> }<br></font></td></tr></tbody></table><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Le cas des deux �crivains :</b><br> Le cas de deux threads qui modifient une m�me variable globale pose un probl�me identique. Les deux threads peuvent vouloir la mettre � jour en m�me temps. Dans ce cas, le dernier � modifier la variable sera le vainqueur. Pour �viter cette situation, m�me rem�de : un mutex ou une section critique. <br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="L'acc�s simultan� � une ressource globale multiple"></a><h2>L'acc�s simultan� � une ressource globale multiple</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Le cas d'une ressource multiple est relativement similaire au cas de la ressource unique. Mais tout d'abord qu'est ce qu'une ressource multiple ? <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Une ressource multiple est une ressource qui peut �tre utilis�e simultan�ment par N threads. Ce qu'on veut dans ce cas, c'est que le N+1�me thread soit bloqu� en attendant que un des N premiers thread lib�re sa ressource. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> L'exemple que j'ai choisi pour illustrer mon propos est le suivant :<br> Il existe une fonction de communication appel�e AcquireCommunicationCanal. Cette derni�re, comme son nom l'indique, ouvre un canal de communication avec un serveur de donn�es. Je sais en outre que je peux ouvrir au maximum 3 canaux simultan�ment. Autre pr�cision, AcquireCommunicationCanal n'est pas bloquante. Si pas de canaux dispos, elle renvoie NULL. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Dans le code que je vous propose, j'ai un lot de 10 threads qui veulent communiquer avec le serveur de donn�es. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici le code erron� qu'on pourrait avoir envie d'�crire en premi�re instance : <table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> for (int i=1; i<=10; i++)<br> {<br> CloseHandle(CreateThread(NULL,0,COMMFct,NULL,0,NULL));<br> }<br> . . .<br><br> DWORD WINAPI COMMFct(LPVOID pData)<br> {<br> HANDLE hCanal;<br><br> . . .<br> hCanal = AcquireCommunicationCanal();<br> if (hCanal)<br> SendData(hCanal,szData);<br> . . .<br> }<br></font></td></tr></tbody></table><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Si on trace ce code, on va vite se rendre compte que en lan�ant tous les threads en pagaille, seuls trois vont obtenir un canal de communication et les septs autres ne communiqueront pas. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> La dessus, on j'en entends d�j� certains : � ho mais c'est pas grave, on va effectuer une boucle et on va appeler sans rel�che AcquireCommunicationCanal jusqu'� ce qu'on obtienne un handle valide �. L� je r�ponds : � Oui mais il y a beaucoup mieux �. En effet une pareille solution n'est ni plus ni moins d'un syst�me de pooling qui gaspille du temps CPU pour par grand-chose. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Une meilleure solution consisterait � s'assurer que seuls trois threads soient en mesure d'appeler la fonction AcquireCommunicationCanal. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Nous voici donc de retour avec nos jetons ;-) Pour se sortir de la situation, nous allons cr�er un jeton muni d'un compteur. Ce compteur nous allons l'initialiser � trois. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Quand un thread va vouloir obtenir le jeton, le syst�me va v�rifier le compteur. Si ce dernier est sup�rieur � z�ro, le thread obtiendra une instance du jeton et le compteur sera d�cr�ment� d'une unit�. Si par contre le compteur est d�j� � z�ro, le thread sera mis en attente jusqu'� ce qu'un autre rende son jeton. Effectivement rendre un jeton, incr�mente le compteur. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Le jeton multi-instance ou s�maphore.</b><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><div align="center"><center><table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="90%"><tbody><tr><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Op�ration</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Fonction Win32</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Remarques</font></b></td></tr><tr><td class="text4" valign="top"> Cr�er </td><td class="text4" valign="top"><b>CreateSemaphore</b></td><td class="text4" valign="top"><ul><li><b></b> On d�termine le nombre total de jetons </li><li><b></b> On peut se r�server 1 ou plusieurs jetons d'embl�e </li></ul></td></tr><tr><td class="text4" valign="top"> Obtenir </td><td class="text4" valign="top"> Wait functions : <ul><li><b></b><b>WaitForSingleObject</b></li><li><b></b> ... </li></ul></td><td class="text4" valign="top"> </td></tr><tr><td class="text4" valign="top"> Rendre </td><td class="text4" valign="top"><b>ReleaseSemaphore</b></td><td class="text4" valign="top"> </td></tr><tr><td class="text4" valign="top"> D�truire </td><td class="text4" valign="top"><b>CloseHandle</b></td><td class="text4" valign="top"> </td></tr></tbody></table></center></div><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici directement le code utilisant un s�maphore, si vous avez compris l'utilisation du mutex, vous n'aurez aucun mal � comprendre le code ci-dessous. <table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> HANDLE g_hSema;<br><br> // 3 jetons et tous les trois dispo<br> g_hSema = CreateSemaphore(NULL,3,3,NULL);<br> for (int i=1; i<=10; i++)<br> {<br> CloseHandle(CreateThread(NULL,0,COMMFct,NULL,0,NULL));<br> }<br> . . .<br><br> DWORD WINAPI COMMFct(LPVOID pData)<br> {<br> HANDLE hCanal;<br><br> . . .<br> __try<br> {<br> // Prendre 1 jeton<br> WaitForSingleObject(g_hSema,INFINITE);<br> hCanal = AcquireCommunicationCanal();<br> SendData(hCanal,szData);<br> }<br> __finally<br> {<br> // Et le rendre ensuite<br> ReleaseSemaphore(hSema,1,NULL);<br> }<br> . . .<br> }<br></font></td></tr></tbody></table><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Dans ce cas ci, 3 threads vont obtenir un jeton (ou instance du s�maphore) et 7 vont �tre bloqu�s. Ils se d�bloqueront au fur et � mesure que les threads rendront leurs jetons. Voici une mani�re relativement �l�gante de g�rer 3 ressources pour 10 threads ! <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Pour la derni�re partie de cet article, je vais donner deux autres exemples courants de synchronisation de threads. <br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Un thread d�marre lorsqu'un autre se termine"></a><h2>Un thread d�marre lorsqu'un autre se termine</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Situation</b> : Un thread A r�colte des informations d'un port s�rie. Un thread B traite les donn�es r�colt�es par A. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Contrainte</b> : Le thread B ne doit travailler que lorsque le thread A a termin� son travail de r�ception. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Solution</b> : <br> Le thread B doit attendre que le thread A se soit termin� avant de traiter les donn�es. Pour d�tecter la fin d'un thread, on peut utiliser le handle sur ce thread. En effet le handle d'un thread est synchronisable, c�d qu'il poss�de un �tat signal�/non signal�. Un thread est non signal� lorsqu'il est en cours d'ex�cution. Il est signal� d�s qu'il s'arr�te. Evidemment cela tombe rudement bien, parce que les api WaitForXXX me permettent de savoir lorsqu'un objet devient signal�. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>L'exemple</b> :<br><table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> HANDLE h1,h2;<br><br> h1 = CreateThread(NULL,0, ThreadA,NULL,0,NULL);<br> // on passe le handle du thread A au thread B<br> h2 = CreateThread(NULL,0, ThreadB,(LPVOID)h1,0,NULL);<br><br> DWORD WINAPI ThreadA(LPVOID pdata)<br> {<br> HANDLE hCOM;<br> hCOM = CreateFile(...);<br> ReadFile(hCOM,...);<br><br> return 0;<br> }<br><br> DWORD WINAPI ThreadB(LPVOID pdata)<br> {<br> // On r�cup�re le handle du thread A<br> HANDLE hThreadA = (HANDLE) pdata;<br><br> // Attendre que le thread A soit signal� (termin�)<br> WaitForSingleObject(hThreadA, INFINITE) ;<br><br> // Traiter les donn�es<br> ...<br> }<br></font></td></tr></tbody></table><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Un thread d�marre son traitement sur base d'un �v�nement ext�rieur"></a><h2>Un thread d�marre son traitement sur base d'un �v�nement ext�rieur</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Situation</b> : Un thread A et un thread B d�sire se passer la main r�guli�rement. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Contrainte</b> : Quand un thread travaille, l'autre est bloqu� et vice et versa <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Solution</b> : Pour synchroniser les deux threads, nous allons utiliser deux objets du noyau de type Event. Un event est un objet synchronisable et donc un thread peut s'enqu�rir de son statut signal�/non-signal�. Le gros int�r�t de l'Event est que nous pouvons totalement contr�ler son statut. Win32 offre des fonctions qui permettent de le signaler ou de ne pas le signaler. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Il existe deux types d'Event. L'Event automatique et l'Event manuel. La finalit� des deux est identique. La diff�rence r�side dans leurs aptitudes � repasser au statut non-signal�. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Un Event automatique repasse non-signal� d�s que un thread qui �tait en attente est d�bloqu�. Tr�s utile quand vous voulez �tre s�r de ne d�bloquer qu'un seul thread � la fois. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Un Event manuel d�bloquera et laissera passer tous les threads tant qu'il sera signal�. Pour le remettre � son statut non-signal�, vous devrez effectuer un appel � la fonction Win32 <b>ResetEvent</b>. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici un exemple de code qui illustre mon propos. Un thread A et un thread B se passent la main ad vitam eternam. <table width="100%"><tbody><tr><td bgcolor="#cccccc" width="100%"><font class="textcode"> HANDLE g_h1,g_h2;<br><br> // Event pour thread 1 cr�� directement avec statut signal�<br> // Ceci me permet de faire en sorte que ce soit le thread<br> // 1 qui commence le travail<br> g_Thread1GoToWork = CreateEvent(NULL,FALSE,TRUE,NULL);<br><br> // Event pour thread 2 non-signal�<br> g_Thread2GoToWork = CreateEvent(NULL,FALSE,FALSE,NULL);<br><br> CloseHandle(CreateThread(NULL,0, ThreadA,NULL,0,NULL));<br> CloseHandle(CreateThread(NULL,0, ThreadB,NULL,0,NULL));<br><br> . . .<br><br> DWORD WINAPI ThreadA(LPVOID pdata)<br> {<br> for(;;)<br> {<br> // Attendre signal du thread 2<br> WaitForSingleObject(g_Thread1GoToWork,INFINITE);<br><br> . . . // Faire qqch<br><br> // Ensuite donner ordre au thread2 de se r�veiller<br> SetEvent(g_Thread2GoToWork);<br><br> }<br><br> return 0;<br> }<br><br> DWORD WINAPI ThreadB(LPVOID pdata)<br> {<br> for(;;)<br> {<br> // Attendre �v�nement du thread 1<br> WaitForSingleObject(g_Thread2GoToWork,INFINITE);<br><br> . . . // Faire qqch<br><br> // Ensuite repasser la main au thread 1<br> SetEvent(g_Thread1GoToWork);<br><br> }<br><br> return 0;<br> }<br></font></td></tr></tbody></table><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Quelques remarques concernant les exemples de code de cet article"></a><h2>Quelques remarques concernant les exemples de code de cet article</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><ol><li><b></b> Dans tous les appels aux fonctions WaitForSingleObject, j'ai opt� pour une attente infinie. Je l'ai fait pour la simplicit� des exemples. Ceci dit vous pouvez sp�cifier un timeout pour l'attente d'un objet. Si toutefois, l'objet n'a pas �t� signal� dans le temps imparti, WaitForSingleObjet renverra la valeur WAIT_OBJECT_TIMEOUT </li><li><b></b> Ceci m'am�ne naturellement � la seconde constatation. Je n'ai jamais test� le code de retour de WaitForSingleObject. Ce n'est pas � conseiller. Si je fais une attente infinie, je ne risque pas d'obtenir un timeout, ceci dit il se pourrait que l'objet sur lequel j'effectue mon attente soit d�truit, dans ce cas WaitForSingleObject me reverra un code WAIT_OBJECT_ABANDONNED. Bref testez le code retour des fonctions WaitForXXX. </li><li><b></b> De mani�re g�n�rale, je vous conseille la lecture du MSDN concernant les fonctions Win32 que j'ai expos�es ici. En effet cet article est bien loin de couvrir toutes les finesses de la synchronisation. </li></ol><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Conclusion"></a><h2>Conclusion</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Que retenir de tout cela ? <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Tout d'abord que la synchronisation des threads se concr�tise dans 95% des cas par une attente sur un objet du noyau dit synchronisable. L'attente se fait par l'appel � une fonction du genre WaitForSingleObject, WaitForMultipleObjects, MsgWaitForMultipleObjects... Si l'objet est non-signal�, ces fonctions sont bloquantes, si l'objet est signal� l'attente se termine. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Ensuite conna�tre les diff�rents types d'objets synchronisables est un plus. Pour chaque type d'objet, Microsoft d�fini la signification de l'�tat signal�/non signal�. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Voici quelques exemples : <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><div align="center"><center><table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="90%"><tbody><tr><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Type d'objet</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Statut</font></b></td><td class="text4" bgcolor="#666666"><b><font color="#fffaea">Signification</font></b></td></tr><tr><td class="text4" valign="top">Process</td><td class="text4" valign="top">Non-signal�</td><td class="text4" valign="top">Le process est actif</td></tr><tr><td class="text4" valign="top"> </td><td class="text4" valign="top">Signal�</td><td class="text4" valign="top">Le process est termin�</td></tr><tr><td class="text4" valign="top">Thread</td><td class="text4" valign="top">Non-signal�</td><td class="text4" valign="top">Le thread est actif</td></tr><tr><td class="text4" valign="top"> </td><td class="text4" valign="top">Signal�</td><td class="text4" valign="top">Le thread est termin�</td></tr><tr><td class="text4" valign="top">Socket</td><td class="text4" valign="top">Non-signal�</td><td class="text4" valign="top">Pas d'�v�nement sur le socket</td></tr><tr><td class="text4" valign="top"> </td><td class="text4" valign="top">Signal�</td><td class="text4" valign="top">Un �v�nement a eu lieu sur le socket (donn�es dispo ...)</td></tr><tr><td class="text4" valign="top">Event</td><td class="text4" valign="top">Non-signal�</td><td class="text4" valign="top">C'est vous qui donnez la signification</td></tr><tr><td class="text4" valign="top"> </td><td class="text4" valign="top">Signal�</td><td class="text4" valign="top">C'est vous qui donnez la signification</td></tr></tbody></table></center></div><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Sur l'auteur"></a><h2>Sur l'auteur</h2><h3></h3><img alt="" src="multithread2.mspx_fichiers/laurentdocquir.jpg" align="right" border="0"><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Laurent a d�but� sur un Sinclair ZX Spectrum � l'age de 12 ans. C'est � ce moment qu'il a attrap� le virus de la programmation. Il a ensuite migr� sur Atari ST (une machine formidable, d'apr�s lui). Sur ST il a principalement fait du GFA Basic et du Lattice C. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> En 1996, il a rejoint <a target="_blank" href="http://www.ezos.com/">Ezos</a>, une soci�t� sp�cialis�e dans les technologies Microsoft. Ses comp�tences sont principalement situ�es en Win32, COM/DCOM. Depuis 1999, apr�s un bref s�jour chez Microsoft � Seattle, Laurent s'est sp�cialis� dans le d�veloppement d'applications mobiles pour les appareils Windows CE. En dehors du travail, il a deux passions : <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><ul><li><b></b>Tout d'abord la famille! Sa femme et lui ont trois merveilleux petits diables: Antoine, Thomas & Simon. </li><li><b></b>Une collection de vieux micro-ordinateurs que vous pouvez d�couvrir sur le net � l'adresse suivante: <a target="_blank" href="http://www.chez.com/ldocquir/">http://www.chez.com/ldocquir/</a>. Si toutefois vous �tes en mesure de lui donner petit un coup de main, n'h�sitez pas � le contacter.</li></ul><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Laurent est aussi mod�rateur d'un forum <a target="_blank" href="http://www.codeppc.com/">CodePPC</a> d�di� au d�veloppement C++ pour Windows CE. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"> Vous pouvez contacter Laurent aux adresses suivantes: <a target="" href="mailto:ldocquir@hotmail.com">ldocquir@hotmail.com</a> ou <a target="" href="mailto:ldo@ezos.com">ldo@ezos.com</a>. <br></div></div></div></td></tr></tbody></table><!--NOINDEX_START--></td></tr></tbody></table><br style="line-height: 1px; overflow: hidden;" clear="all"><table id="msviFooter" cellpadding="0" cellspacing="0" width="100%"><tbody><tr valign="bottom"><td id="msviFooter2" style=""><div id="msviLocalFooter"><nobr><a href="http://go.microsoft.com/?linkid=317114">Uw gegevens</a> |</nobr><wbr><nobr><a href="http://www.microsoft.com/belux/nl/contactus">Contacteer ons</a> |</nobr><wbr><nobr><a href="mailto:msdnbewm@microsoft.com?subject=Feedback" target="_parent">Feedback</a> |</nobr><wbr><nobr><a href="http://www.microsoft.com/belux/nl/msdn/community/newsletter.mspx">Newsletter for developers</a></nobr></div><div id="msviGlobalFooter"><span dir="ltr">�2005 Microsoft Corporation. Alle rechten voorbehouden. </span><nobr><a href="http://www.microsoft.com/belux/nl/misc/cpyright.htm" target="_parent">Gebruiksrechtenovereenkomst</a> |</nobr><wbr><nobr><a href="http://www.microsoft.com/library/toolbar/3.0/trademarks/nl-be.mspx">Handelsmerken</a> |</nobr><wbr><nobr><a href="http://www.microsoft.com/info/nl-be/privacy.mspx">Privacyverklaring</a></nobr></div></td><td bgcolor="#669aff" width="105"><img src="multithread2.mspx_fichiers/text.jpg" alt="Microsoft" title="" border="0" height="29" width="105"></td></tr></tbody></table><layer visibility="hide"></layer><div style="display: none;"><img alt="" src="multithread2.mspx_fichiers/trans_pixel.gif" border="0" height="0" hspace="0" vspace="0" width="0"></div></body></html>