File "multithread2.mspx.htm"
Full Path: /home/analogde/www/Emile/PATRICE/Prog/multithread2.mspx.htm
File size: 49.23 KB
MIME-type: text/html
Charset: 8 bit
<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 cration 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>Rsum: </b>Laurent discute des problmes lis l'excution concurrente de plusieurs threads au sein d'une mme 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 premire partie</a>
de l'article, nous avons dcouvert la notion de thread et surtout nous
avons fait le tour des fonctions Win32 qui permettent de les grer. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Dans cette seconde partie, nous allons discuter des problmes lis
l'excution concurrente de plusieurs threads au sein d'une mme
application. En effet ce n'est pas le tout de crer 50 threads, encore
faut il pouvoir avoir une emprise sur la manire, l'ordre dans lequel
ils s'excutent. <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'accs simultan une ressource globale unique
</li><li><b></b>
L'accs simultan une ressource globale multiple
</li><li><b></b>
Un thread commence son excution quand un prcdent se termine
</li><li><b></b>
Un thread commence son excution sur base d'un vnement extrieur
</li></ul><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="L'accs simultan une ressource globale unique"></a><h2>L'accs 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 mme espace
d'adressage virtuel. En d'autres termes, et pour tre clair, deux
threads provenant d'une mme application peuvent partager une ou
plusieurs zones mmoires. Pratiquement une telle zone mmoire 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 mmoire
</li></ul>
Lorsque deux threads accdent une mme zone mmoire, il est possible
qu'ils essaient de changer ou de lire sa valeur en mme temps. Trois
cas peuvent se poser : <ol><li><b></b> Deux lecteurs : les deux threads accdent la
variable en lecture. Ce cas n'est pas trs courant, nanmoins il ne
pose pas de problmes particuliers. </li><li><b></b>
Un lecteur, un crivain : un thread est matre de la valeur de la zone mmoire, 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 mmoire.
</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, considrez 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(); // dure : 30 min<br>
}<br>
}<br>
}<br><br>
DWORD WINAPI Writer(LPVOID p)<br>
{<br>
for (;;)<br>
{<br>
// Toute les minutes la temprature 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 problme est le suivant : imaginons que au moment ou le thread 1
(Reader) est sur le point de commencer un lavage, il dtecte une
temprature de 60. Cette dernire est acceptable puisque infrieure
70, le thread 1 lance donc la procdure de lavage. Cette procdure
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. Aprs exactement 11 minutes, la temprature aura
atteint 71 ce qui n'est plus une valeur acceptable pour le linge.
Malheureusement la fonction LaverLinge va encore s'excuter pendant 19
minutes. Pas besoin de vous faire un dessin pour vous faire comprendre
que le linge ne pourra plus tre mis que par poupe 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 problme. Ce problme arrive gnralement 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 change. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Pour solutionner ce problme, il suffit de se dire que lorsque un
lavage est en cours, on se limite garder la temprature 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 trs simple. Nous allons crer un jeton et dcrter que pour
modifier la temprature de l'eau de 1, il faut imprativement
s'approprier le jeton. Evidemment l'intrt du jeton est que seul un
thread peut en avoir la proprit 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 (cd 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 systme 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 temprature, on peut facilement le contrler. 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 priode de lessivage.
Problme rsolu. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>C'est bien beau tout cela mais comment j'implmente mon jeton ?</b><br>
Le systme Win32 propose deux implmentations d'un jeton simple : le mutex et la section critique.
<br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Les oprations que nous voulons excuter avec un jeton sont les suivantes : crer, obtenir, rendre et dtruire.
<br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><i>Implmentation sous forme de mutex</i><br>
Le tableau ci-dessous donne les fonctions Win32 associes au mutex pour les 4 oprations :
<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">Opration</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">
Crer
</td><td class="text4" valign="top"><b>CreateMutex</b></td><td class="text4" valign="top"><ul><li><b></b>
On peut obtenir le jeton ds sa cration
</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 dtruit ou
encore qu'un certain dlai 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">
Dtruire
</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 consquence :
<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(); // dure : 30 min<br>
}<br>
}<br>
__finally<br>
{<br>
// Rendre le jeton aprs que la lessive soit termine<br>
ReleaseMutex(g_hMutex);<br>
}<br>
}<br>
}<br><br>
DWORD WINAPI Writer(LPVOID p)<br>
{<br>
for (;;)<br>
{<br>
// Toute les minutes la temprature 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
gnr dans la fonction LaverLinge, je rendrai quand mme le jeton
proprement. Dans le cas contraire une exception non gre 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>Implmentation sous forme de section critique.</i><br>
Contrairement au mutex qui est un objet du noyau, la section critique
est une simple structure en mmoire. La finalit de la section critique
est la mme que celle du mutex. Le seul intrt d'une section critique
est qu'elle ne ncessite aucun service du noyau, elle consomme moins de
ressources systmes 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 mme processus. Un mutex ,par contre,
peut se voir attribuer un nom lors de l'appel Win32 <b>CreateMutex</b>. Dans ce cas, un thread rsidant dans un autre processus peut obtenir un handle sur ce mme mutex en appellant <b>CreateMutex</b> ou <b>OpenMutex</b> avec le mme nom.
<br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Voici le tableau des fonctions lies 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">Opration</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">
Crer
</td><td class="text4" valign="top"><b>Dclarer 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 initialise 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">
Dtruire
</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(); // dure : 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 temprature 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 mme variable globale pose un
problme identique. Les deux threads peuvent vouloir la mettre jour
en mme temps. Dans ce cas, le dernier modifier la variable sera le
vainqueur. Pour viter cette situation, mme remde : un mutex ou une
section critique. <br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="L'accs simultan une ressource globale multiple"></a><h2>L'accs 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 utilise
simultanment par N threads. Ce qu'on veut dans ce cas, c'est que le
N+1me thread soit bloqu en attendant que un des N premiers thread
libre 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 appele
AcquireCommunicationCanal. Cette dernire, comme son nom l'indique,
ouvre un canal de communication avec un serveur de donnes. Je sais en
outre que je peux ouvrir au maximum 3 canaux simultanment. Autre
prcision, 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 donnes.
<br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Voici le code erron qu'on pourrait avoir envie d'crire en premire 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 lanant 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 dj certains : ho mais c'est pas grave,
on va effectuer une boucle et on va appeler sans relche
AcquireCommunicationCanal jusqu' ce qu'on obtienne un handle valide .
L je rponds : Oui mais il y a beaucoup mieux . En effet une
pareille solution n'est ni plus ni moins d'un systme 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 crer 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 systme va vrifier le
compteur. Si ce dernier est suprieur zro, le thread obtiendra une
instance du jeton et le compteur sera dcrment d'une unit. Si par
contre le compteur est dj zro, le thread sera mis en attente
jusqu' ce qu'un autre rende son jeton. Effectivement rendre un jeton,
incrmente le compteur. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Le jeton multi-instance ou smaphore.</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">Opration</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">
Crer
</td><td class="text4" valign="top"><b>CreateSemaphore</b></td><td class="text4" valign="top"><ul><li><b></b>
On dtermine le nombre total de jetons
</li><li><b></b>
On peut se rserver 1 ou plusieurs jetons d'emble
</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">
Dtruire
</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 smaphore, 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
smaphore) et 7 vont tre bloqus. Ils se dbloqueront au fur et
mesure que les threads rendront leurs jetons. Voici une manire
relativement lgante de grer 3 ressources pour 10 threads ! <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Pour la dernire 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 dmarre lorsqu'un autre se termine"></a><h2>Un thread dmarre lorsqu'un autre se termine</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Situation</b> : Un thread A rcolte des informations d'un port srie. Un thread B traite les donnes rcoltes 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 rception.
<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 donnes. Pour dtecter la fin d'un thread, on peut utiliser
le handle sur ce thread. En effet le handle d'un thread est
synchronisable, cd qu'il possde un tat signal/non signal. Un
thread est non signal lorsqu'il est en cours d'excution. Il est
signal ds qu'il s'arrte. 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 rcupre 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 donnes<br>
...<br>
}<br></font></td></tr></tbody></table><br></div></div><div style="margin-left: 0px; margin-bottom: 0px;"><a name="Un thread dmarre son traitement sur base d'un vnement extrieur"></a><h2>Un thread dmarre son traitement sur base d'un vnement extrieur</h2><h3></h3><div class="text4" style="padding-top: 0px; padding-bottom: 10px;"><b>Situation</b> : Un thread A et un thread B dsire se passer la main rgulirement.
<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'enqurir de son statut signal/non-signal. Le gros
intrt de l'Event est que nous pouvons totalement contrler 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 diffrence rside 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 ds que un thread qui tait en
attente est dbloqu. Trs utile quand vous voulez tre sr de ne
dbloquer qu'un seul thread la fois. <br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Un Event manuel dbloquera 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 rveiller<br>
SetEvent(g_Thread2GoToWork);<br><br>
}<br><br>
return 0;<br>
}<br><br>
DWORD WINAPI ThreadB(LPVOID pdata)<br>
{<br>
for(;;)<br>
{<br>
// Attendre vnement 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 spcifier 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'amne 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 dtruit, dans ce cas
WaitForSingleObject me reverra un code WAIT_OBJECT_ABANDONNED. Bref
testez le code retour des fonctions WaitForXXX. </li><li><b></b> De manire gnrale, je vous conseille la
lecture du MSDN concernant les fonctions Win32 que j'ai exposes 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 concrtise 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 connatre les diffrents types d'objets synchronisables est un
plus. Pour chaque type d'objet, Microsoft dfini 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'vnement 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 vnement a eu lieu sur le socket (donnes 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 dbut 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'aprs 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 socit spcialise dans les technologies Microsoft. Ses
comptences sont principalement situes en Win32, COM/DCOM. Depuis
1999, aprs un bref sjour chez Microsoft Seattle, Laurent s'est
spcialis dans le dveloppement 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 dcouvrir 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'hsitez pas le contacter.</li></ul><br></div><div class="text4" style="padding-top: 0px; padding-bottom: 10px;">
Laurent est aussi modrateur d'un forum <a target="_blank" href="http://www.codeppc.com/">CodePPC</a> ddi au dveloppement 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>