mardi 30 novembre 2010

Les sciences ou l'informatique, une histoire de l'évolution identique

Evolution des sciences
Avant d'entamer le cœur du sujet, il me faut parler de l'évolution des sciences.
J'ai en effet remarqué qu'il existe un corolaire entre l'évolution des sciences et l'évolution de l'informatique. 


En 1800 (il y a seulement 200 ans), Volta découvrit la pile voltaïque.
En étudiant cette extraordinaire découverte et en cherchant à expliquer pourquoi le passage de l'électricité dans un fil déviait une boussole, Faraday découvrit et formalisa les relations entre champ magnétique et courant électrique (l'induction électromagnétique).
Faraday avait même conçut le premier prototype scientifique du moteur électrique.

En 1864, Maxell unifia les différentes théories relatives au magnétisme qu'il formalisa dans les théories de l'électromagnétisme. A dater de ce jour, il existait des relations entre charge électrique, courant électrique, les aimants et les ondes électromagnétiques (lumières, onde radio).
Ces mêmes théories qui furent utilisées d'abord par Graham Bell qui inventa le téléphone et bien plus tard dans les tubes cathodiques des premières télévisions, dans les théories d'Einstein sur la relativité, ...
L'histoire pourrait se poursuivre ainsi jusqu'à nos jours.

Ce qu'il est important de retenir, c'est qu'il y a 200 ans (et un peu moins), il était possible à une seule personne d'aborder suffisamment de facettes des sciences (math, chimie, physique, biologie, optique, astronomie, etc) pour faire des découvertes majeures.
Ces découvertes ne nécessitaient pas d'énormes investissements financiers.
Les expériences ne nécessitaient pas une implication à temps plein.

En 2010, à peine plus de 200 ans plus tard, la moindre nouvelle découverte scientifique réclame un investissement de plusieurs millions d'Euro, la construction d'appareillage titanesque (le LHC fait 26 km de long), la mise en œuvre d'équipes entières (de quelques dizaines de personnes à quelques milliers de personnes).
Mais surtout, et ce qui est le plus marquant, c'est que le savoir à accumuler pour atteindre ces découvertes ne sait plus résider dans une seule tête.
Aujourd'hui, n'importe quelle science de base (ex: la physique) est devenue à ce point complexe qu'une seule personne n'est même plus capable d'en entrapercevoir tous les tenants et les aboutissants.
Quelle évolution!

Vulgariser les sciences
La vulgarisation scientifique se perd dans toute cette complexité des sciences.
Cela devient un exercice de plus en plus difficile et de moins en moins pratiqué.
Et si le monde scientifique s'en est peu préoccupé ces dernières décennies, certains scientifiques reviennent en force sur le devant de la scène pour vulgariser. C'est vital pour la survie de la science.


Nous utilisons tous des objets Hi-Tech (GSM, LCD, lecteur MP3) issus des découvertes scientifiques passées mais nous ne savons pas comment ils fonctionnent.
Si ce n'est pas forcément important au jour le jour, le manque de vulgarisation scientifique aura un impact négatif sur la recherche scientifique.
A terme, la population ne comprendra plus ce que les scientifiques font, ni pourquoi ils le font. La population n'entrevoira pas les débouchés que les travaux scientifiques nous offriront. Le GSM que nous utilisons tous les jours est un de ces résultats.
Dans un tel cas de figure, les scientifiques perdront l'estime du public, ils seront vus comme des "gens bizarres" qui coûtent beaucoup d'argent à la collectivité.
C'est pourtant cette même collectivité qui élit ses représentants et ces représentants qui votent les budgets (y compris ceux de la recherche scientifique).



Evolution de l'informatique
D'un point de vue de la gestion informatique et de la programmation, les technologies informatiques atteignent aujourd'hui les limites de l'humainement absorbable, surtout pour les développeurs.
Tout comme les sciences, l'informatique atteint une telle complexité qu'il n'est plus possible pour une seule personne de maîtriser tous les tenants et aboutissants d'une infrastructure informatique ou d'un développement logiciel.
Faire un bon logiciel d'envergure réclame des connaissances poussées dans de nombreux domaines techniques et langages de programmation.
Avec la généralisation des machines multi-processeurs, la programmation performante est devenue encore plus compliquée.

Rien que la mise en place d'une infrastructure de production (et sa maintenance) est un travail à temps plein réclamant un savoir étendu (matériel, système d'exploitation, réseau, télécom, administration, optimisation, sécurité, firewall, DNS, téléphonie, ...).
Dans le même ordre de grandeur, un développement Internet réclame de nombreuses compétences dans de nombreux domaines (base de données, les indispensables et multiples langages de programmation, html, styles, xml/xsl, plateforme de développement comme par exemple .Net, développements Asp, multi-threading et synchronisation, des frameworks, infographie, encryption, compression, etc).
L'informatique a atteint une telle complexité qu'il faut plusieurs personnes pour maitriser parfaitement l'ensemble des domaines nécessaires.

Certains logiciels sont même à ce point complexes qu'il faut des personnes spécialisées pour gérer la connaissance fonctionnelle du logiciel, le configurer ou le manipuler.

Il est bien loin le temps où une vraie passion pour l'informatique pouvait encore faire de vous un informaticien compétant. Notez la correspondance avec l'évolution des sciences.
Aujourd'hui, une nouvelle technologie telle que Dot.Net est logiquement découpée en nombreux domaines eux-mêmes décrits dans plusieurs publications (en milliers de pages). Difficile pour une seule personne de maitriser une telle étendue de savoir.

Les évolutions futures tels que le Cloud Computing (Windows Azure pour l'environnement Dot.Net) accentuera encore plus ce besoin de connaissances étendues.

Aujourd'hui, l'informaticien n'a pas d'autre choix que de se spécialiser.
Les chefs de projet et directeurs informatiques doivent devenir les vulgarisateurs de demain.

Vulgariser l'informatique en société
Comme dans le cas de la vulgarisation scientifique décrite ci-avant, il est important de vulgariser les techniques informatiques auprès des décideurs. 

Les patrons ont des objectifs financiers et s'organisent en fonction de ces objectifs.
Bien que l'informatique soit aujourd'hui une des pierres angulaires de l'organisation économique d'une société, peu de patrons disposent des connaissances minimum pour pouvoir apprécier justement l'impact de leurs décisions.
A défaut de comprendre les techniques et développements informatiques, il est normal que ces derniers fassent régulièrement de mauvais choix.
Par sa complexité et par son manque de communication, l'informatique, les développements informatiques et surtout ses informaticiens se sont eux-mêmes isolés des décideurs.
Faut-il rappeler le stéréotype des informaticiens?

Cette situation déplorable cause beaucoup de nombreux heurts de perception et de communication dans une société. Il faut aussi des vulgarisateurs en informatique.

La course informatique
A contrario, il faut reconnaître que les grands acteurs informatiques (concepteurs de système d'exploitation et matériels informatiques) organisent une course technologique.
Une marche effrénée est organisée pour habilement forcer le renouvellement des parcs informatiques (logiciel et matériel).
Si l'évolution semble certes nécessaire, ces dernières années j'ai souvent eu l'impression que ces acteurs provoquaient le besoin en promettant monts et merveilles.
Au final de cette évolution, des promesses non tenues et de nouveaux problèmes.
Les décideurs l'ont bien compris, la sortie d'un nouveau système d'exploitation mets maintenant plus de temps à être adopté par les sociétés. A contrario, cette réaction logique gêne quelques-fois l'adoption de techniques ou nouveautés, qui elles, seraient bien utiles.

Maintenir les connaissances à jour
Les technologies informatiques (et la programmation) sont en constante évolution. Comme décrit plus haut, il faut aujourd'hui envisager des spécialisations car l'étendue des connaissances à accumuler devient trop vaste.
Mais même dans un domaine particulier, il est nécessaire d'être attentif à l'évolution, au risque d'être dépassé assez rapidement.
Il y a 10 ans encore, lire quelques articles suffisait à accumuler le savoir nécessaire pour suivre l'évolution technologique.
Aujourd'hui, c'est des livres de 500 pages qu'il faut lire, ou pouvoir bénéficier de formations spécialisées.

Même si je suis convaincu qu'il existe nombre de sociétés avec une politique de formation correcte, je déplore malheureusement la politique de nombreux autres  employeurs dans ce domaine.  J'en parle en connaissance de cause.
Ils attendent que les informaticiens connaissent tout de leur domaine sans jamais devoir investir le moindre Euro pour maintenir cette connaissance à jour.
Il est attendu des informaticiens qu'ils se tiennent au courant par leurs propres moyens, avec leurs propres fonds et sur leur temps privé.
L'achat d'un magazine informatique (MSDN Magazine) peut faire l'objet d'âpres discussions. Convaincre l'employeur du bien fondé d'une formation est souvent un parcours du combattant. Et si le sujet est suffisamment pointu pour opter pour l'achat d'un livre spécialisé, il faudra convaincre l'employeur de l'acheter. Essuyer un refus si l'on demande du temps de travail pour le lire et étendre son savoir dans son domaine de compétence (véridique et dans un service de R&D).
J'ai même vu un employeur rester impassible devant un développeur demandant à mieux connaître les aspects du métier pour lequel il travaillait.

Il est important pour les employeurs de comprendre l'intérêt de garder quelqu'un de compétant dans ses services mais aussi de réaliser que c'est un investissement qu'il doit pouvoir faire.
Il est important pour les techniciens et développeurs informatiques de rester en formation constante afin d'offrir le meilleur service dans les meilleures conditions.

lundi 29 novembre 2010

Partages Windows7 - Ubuntu

Ubuntu.fr contient un excellent article concernant le partage de ressource à l'aide de Samba, NFS et SSH.
Pour les partages entre Windows et Ubuntu, c'est le service Samba qu'il faut activer.
L'article est assez complet mais il manque quelques précisions bien utiles.

Activer le service de partage sous Ubuntu
Pour information, le service Samba est installé et activé uniquement lorsque l'utilisateur Ubuntu active son premier partage de répertoire.
Le plus simple étant encore de partager son répertoire publique sous Ubuntu.
Le reste se fait automatiquement.

Windows 7
Si l'accès au partage semble fonctionner parfaitement à l'aide de Windows XP, cela n'est pas aussi facile depuis Windows 7.
Il faut en effet modifier certains paramètres (source sur TomsHardware) sous Windows 7.
Control Panel - Administrative Tools - Local Security Policy 
Local Policies - Security Options 
  • Network security: LAN Manager authentication level = Send LM & NTLM responses 
  • Minimum session security for NTLM SSP = Disable Require 128-bit encryption 
Une fois ces paramètres modifiés, la connexion est immédiate.

Windows 7 Home premium et  Local Security Policy
Je ne dispose personnelement pas de cette version mais il semblerait que le panneau "Local Security Policy" ne soit pas disponible sur cette version.
En fouillant un peu sur le net (ici), il semblerait qu'il soit néanmoins possible de faire le nécessaire en modifiant/ajoutant la clé LmCompatibilityLevel directement dans la base de registre et bien entendu sans oublier de rebooter la machine.

Ajouter/modifier la clé LmCompatibilityLevel dans HKLM|System|CurrentControlSet|Control|Lsa
La clé doit être un DWORD et avoir la valeur 2.

Je n'ai personnellement pas essayé, je ne sais donc pas garantir le résultat. Par contre, merci de faire savoir si cela est concluant.
Plus d'information sont disponibles a propos de LmComaptibilityLevel  sur le site MSDN.
 

Partager une imprimante Ubuntu
J'ai une imprimante HP LasertJet 1005 branchée sur mon PC Ubuntu.
Il est possible de la partager pour y accéder depuis Windows 7.
Voici la marche a suivre:

A faire sous Ubuntu
  • Ouvrir le gestionnaire d'imprimante.
  • Menu Serveur | Paramètres
  • Activer les options suivantes: "publier les imprimantes partagées disponible sur ce système" et "Autoriser l'impression depuis Internet"
  • Fermer la fenêtre des paramètres.
  • Dans le menu contextuel disponible pour l'imprimante, activer l'option "partager"
  • Utilisez la commande suivante dans un terminal pour connaitre le nom de la machine Ubuntu
    more /etc/hostname
  • Utilisez la commande suivante dans un terminal pour connaitre l'adresse IP de la machine
    ifconfig
Sur la machine Windows 7
  • Se connecter sur la machine Ubuntu, ce qui affiche les répertoires partagés et l'imprimante.
    Dans un premier temps, utilisez l'adresse IP pour vérifier que la machine est atteignable directement ( utiliser \\AdresseIp dans le navigateur de fichier).
    Par la suite, tester la connexion à l'aide du nom de la machine ( \\NomDuPcUbuntu ).
    Dans tous les cas, il est préférable d'utiliser le nom du PC car l'adresse IP peut changer au fil du temps.
  • Afficher le menu contextuel de l'imprimante et sélectionner "Connecter".
    Cela va démarrer l'installation de l'imprimante (attention, il vous faut avoir les Drivers Windows à disposition)

vendredi 26 novembre 2010

Windows Azure - Ressources développeur


Vidéo
Références
Articles
IntelliTrace


One of the cool new features of the June 2010 Windows Azure Tools + SDK is the integration of IntelliTrace to allow you to debug issues that occur in the cloud.
Using IntelliTrace to debug Windows Azure Cloud Services

Windows Azure Storage
Service permettant le stockage persistent d'information sur le cloud.
Ce service inclus:
  • du stockage binaire dans les BLOBs (Binary Large Object), 
  • Queue service (message queue), 
  • table service (pour stockage d'information structurée sur laquelle il est possible de faire des queries), 
  • Windows Azure Virtual Hard Drive (VHD) qui permet de monter une disque dur NTFS sur un Blob. Cela permet aux applications de télécharger ou uploader des fichiers directement dans un Blob.
Windows Azure CDN - Content Delivery Network
S'intègre avec Windows Azure Storage, CDN permet d'améliorer la fiabilité et les performance de l'utilisateur final en plaçant les informations physiquement près de lui. CDN permet de délivrer tout type d'objet web (javascript, css, etc), des éléments téléchargeables (soft, document, fichiers), des applications, des streams multimedia, etc. CDN permettrait également de délivrer du contenu et services tels que des Databases Queries, DNS, ...
Windows Azure AppFabric
L'appFabric est une partie de la plateforme Azure qui sert principalement à facilité la construction d'application Hybride.
On retiendra surtout deux modules dans l'appFabric:
  1. Acces Control Service (ACS) permettant l'authentification des connexions et la gestion des règles de connectivité. ACS est un des éléments principaux du Service Bus, il permet à des clients ou applications (cloud ou non-cloud) de s'identifier. L'identification est d'ailleurs assurée par un composant "identity Provider", ce qui permettrait à terme d'autoriser de façon transparente des identifications à partir de login facebook ou twitter.
  2. Service Bus (SB) est l'élément essentiel d'appFabric. Il permet à des applications Cloud et Non-Cloud de communiquer ensemble via une simple connexion internet (de type Http/https). Par exemple, un web-service privé (non publié) fonctionnant dans un data-center propre peut-être publier via service bus de manière à être accessible à des terminaux mobile actif sur des ligne aérienne (seul une connexion internet est requise).
Je recommande vivement le visionnement de la vidéo MSDN: AppFabric Overview (50 min), elle offre une excellente vue d'ensemble du Service Bus et de Access Control Service.

Building Windows Azure Services
Voici une série d'articles MSDN destinés à la mise en place de Services sous Windows Azure. Les articles abordent les différentes facettes techniques à maitriser et explique comment effectuer les développements sur le "Development Fabric" (simulateur du SDK)

    samedi 13 novembre 2010

    La non-communication en entreprise

    Introduction
    Sur le lieu du travail, il est assez courant qu'il y ait une mauvaise communication eu sein d'un même service.
    Souvent, il faut bien l'admettre, supérieur hiérarchiques et subordonnées communiquent mal.
    Cela a souvent pour origine le jeu de pouvoir du supérieur hiérarchique qui ainsi veut maintenir sa supériorité en, l'espère t'il, gérant l'information.

    Note:
    Dans l'article suivant, les dénominations "supérieur hiérarchique" et "manager" seront utilisées de façon équivalentes pour désigner les supérieurs hiérarchiques au sens général du terme.

    L'information c'est le pouvoir
    En effet, gérer l'information c'est gérer le pouvoir. Qui détient l'information détient du pouvoir. Je crois que c'est un fait communément admis.
    Malheureusement, en partant de ce constat, beaucoup de manager (ou responsable hiérarchiques) se servent de l'information pour maintenir leur pouvoir.
    Quoi de plus normal... mais souvent, il le font mal. Et quelques-fois tellement mal que cela impacte très négativement le moral et la production de leurs subordonnés.

    Quelques exemples
    Le cas de figure qui nous concerne, à savoir la non-communication, est très répandu en entreprise.
    Les supérieurs hiérarchiques ne communiquant pas sont malheureusement légion et c'est rarement par ignorance. Pour le cas de mon expérience professionnelle, je fixerais cette proportion à 75% des managers non-communicants.

    Exemple 1:
    Ainsi, si un nouveau collègue est attendu, on ne saura jamais quand il arrive, qui il sera, quel sont ses qualifications, quel sera son travail. Il sera là un jour au matin... et ce sera aux subordonnés de s'organiser au pied levé pour l'accueillir et le former.
    Par la communication, il serait possible de découvrir qu'il lui manquerait tel ou tel qualification importante, que le service à besoin d'être épaulé dans un domaine particulier. Par le manque de communication, cela n'est forcement pas connu lors de la recherche et impactera au final la productivité.
    Il faut relever qu'il est assez rare que les supérieurs non communicants se remettent en question sur leur mauvais choix.
    Exemple 2:
    Si le subordonné doit modifier sa façon de travailler pour des raisons d'organisation, il l'apprendra à la dernière minute. Mais surtout, il apprendra qu'une ou plusieurs réunions auxquelles il aurait dut être convié pour faire part de son expérience se sont déroulées sans lui (cas vécu). Ainsi se prennent des décisions qui n'ont pas toujours beaucoup de sens pratique! Et côté responsabilité, c'est le subordonné qui devra s'arranger pour faire en sorte que les décisions du supérieur soient mises en pratiques et cela deviendra la responsabilité du subordonné.
    Il y a souvent d'autres options plus commodes et plus motivantes, pour les connaître, il faut savoir communiquer. Impliquer un subordonné le rend volontairement responsable de ses choix.
    Exemple 3:
    Les supérieurs hiérarchiques aux connaissances techniques limitées craignent quelques-fois les connaissances de leurs subordonnés.
    Ainsi, ce type de supérieur hiérarchique ne communique volontairement pas avec le subordonné craint.
    Ainsi isolé, le subordonné ne peut pas partager ses idées et ces dernières ne progressent pas dans la société.
    Ce manque de communication est une grosse perte pour la société... parce que tous les subordonnés ne souhaitent pas prendre la place de leur supérieurs, certains souhaitent simplement partager leur expérience pour le bien de tous.
    Il est même courant que les éventuelles idées émissent soient broyées et brisées systématiquement, qu'elle soient bonnes ou pas. Peut-être ressortiront-elles après le départ de l'employé désabusé.
    Un minimum de psychologie pourrait permettre à ces manager de faire la différence entre les vrais ambitieux (destructeurs) et les vrais collaborateurs.
    Exemple 4:
    Ne jamais recevoir de réponse aux e-mails de suggestions ou e-mail mettant en lumière des problèmes identifiés.
    Une autre technique liées aux e-mail consiste à prendre connaissance du message mais ne pas y répondre, par principe, avant plusieurs jours.
    Si cette technique peut offrir l'avantage de la réflexion lorsque cela est nécessaire, son usage systématique est une forme de non-communication harcelante (surtout si la technique est connue) lorsqu'elle est mise en œuvre dans une relation hiérarchique.
    Lorsque cette technique est pratiquée par un supérieur hiérarchique, elle creuse malheureusement le fossé du pouvoir (celui qui peut faire attendre sa réponse).
    Ce type de non-communication par principe manque d'humanité. Si elle est généralement fort peu appréciée entre collègues, le procédé devient discutable lorsqu'elle est pratiquée dans le cadre d'une relation hiérarchique directe car

    non seulement cette pratique marque la différence de statut mais dévalorise le subordonné qui lui sait qu'il attend le bon vouloir (souvent dans l'impuissance) du supérieur.
    Cela rabaisse/rappelle volontairement le subordonné à sa condition. Est-ce d'ailleurs bien nécessaire ?
    Cette pratique est d'ailleurs assez courante avec les demandes de congé.


    La non-communication, le stress, la démotivation et la production
    La non-communication engendre un stress chez les subordonnés.
    Il ne savent jamais rien, vont de surprises en surprises. La moindre information arrivant par des canaux annexes fait l'objet de nombreuses spéculations. Ce n'est pas sain pour une équipe car cela fini par entretenir une mauvaise ambiance générale.
    La non-communication engendre la démotivation chez les subordonnés.
    C'est normal, ne pas communiquer avec quelqu'un (et surtout les informations pertinentes le concernant) c'est faire comme s'il n'existait pas.
    Ne pas se sentir exister pour un subordonné, cela revient à se sentir transparent  et au bout du compte vient la question "Ce que fait est-il vraiment utile? Quel est ma valeur?".
    Si c'est certes une approche radicale, la non-communication est à placer dans les processus d'harcèlement moral car utilisée abusivement la non-communication détruit psychiquement... mais bien entendu, difficile de prouver quoi que ce soit dans ce domaine.

    En étant un tant soit peu éclairé, n'importe quel quidam est capable de comprendre qu'une telle ambiance résultant de la non-communication influencera négativement le rendement et la qualité générale de la production.
    Les gens (subordonnés) produisent plus et mieux lorsqu'ils se sentent bien au travail. C'est encore plus vrai s'ils se sentent l'une des pièces motrice de leur entreprise.

    La confiance et la non-communication
    Une des conséquences du paragraphe précédent est également la fragilité de la relation de confiance dans les relations hiérarchiques.
    Il est difficile de se montrer ouvert et communicant lorsqu'en face l'on retrouve le comportement opposé.
    Par ailleurs, la relation non-communicante aura probablement causé plusieurs heurts au sein de l'équipe qui se retrouve à subir des décisions pas toujours très appropriées/adéquates. Que les heurts soient isolés ou collectifs, le résultat final après quelques mois restera probablement le même, une "perte de confiance" au sens large.


    Les subordonnés en situation de dévalorisation (car c'est l'une des conséquences de la non-communication) peuvent difficilement renouer une relation de confiance. Cela revient à baiser sa garde pour faire une tentative ouverte, ce qui est difficile étant donné l'état d'esprit du subordonné.
    D'autres part, il ne faut pas oublier que dans la situation de dévalorisation, le subordonné longtemps ignoré peut finir par perdre confiance en lui. Encore un point en la défaveur de renouage d'une relation ouverte.

    Faut-il le rappeler, la confiance et la relation de confiance permettent à tous d'offrir le meilleur d'eux mêmes dans les meilleures conditions.
    Elle contribue au bien être et permet à tout un chacun de s'impliquer.
    Cela est stimulant sur le plan personnel et professionnel.
    Cela permet donc d'aboutir à de meilleures performances sur le lieu du travail.
    Tout le monde est gagnant dans une relation de confiance, même l'entreprise.

    Garder le pouvoir
    Ainsi, si par défaut de communication un manager espère garder le pouvoir, il perd également de vue un autre objectif très important... la productivité.
    Dans cet article, je lie beaucoup les mots "information" et "pouvoir", Google démontre la pertinence de cette relation à chaque requête de recherche.

    Mais le mot "pouvoir" laisse cependant trainer l'arrière pensée de "possession" (posséder le pouvoir, le pouvoir de posséder).

    Je voudrais relever que le rôle d'un manager n'est pas de "posséder" mais de "manager" (autrement dit, "d'organiser au mieux"). Le manager n'a pas besoin de pouvoir, ce n'est logiquement pas son rôle.
    Malheureusement, la société humaine et les jeux de pouvoir en entreprise (entre managers) instaure cette nécessité discutable (à mon sens).
    Il est bien regrettable que cela se ressente jusqu'aux niveaux les plus bas de la hiérarchie, là où ce n'est souvent pas nécessaire.


    Le manipulateur et la communication
    Je voudrais ici faire un petit aparté concernant le manipulateur relationnel (voir les articles résumés sur cet autre blog).
    Les manipulateurs relationnels manipulent beaucoup l'information.
    Ils oscillent beaucoup entre l'information exclusive (celle qui attire par le mystère), la rétention d'informations (souvent essentielles) et le mensonge pour manipuler le gens (en faire des amis ou diviser pour régner).

    Il y a également une autre technique plus pernicieuse et beaucoup plus difficile encore à relever.
    Le manipulateur en position de pouvoir mais communiquant des informations à caractère excitant.
    Les informations pertinentes ne sont pas forcement communiquées, par contre des informations excitantes mais réelles qui sont allègrement parsemées au milieu des subordonnés.
    C'est ainsi que l'on pourrait se faire mettre sous le nez les détails des revenus de la société en se faisant dire que le big boss gère mal son affaire et qu' "on" (qui ca "on" ?) pourrait faire mieux à sa place (cas vécu).
    Ou encore que "la direction fait n'importe quoi, ils n'ont qu'à continuer comme ça, c'est leur problèmes ..." (supérieur hiérarchique qui excite ses subordonnés contre la direction. Est-ce vraiment opportun et pertinent? Cas vécu).
    Ou encore, exciter les subordonnés en énumérant tous les problèmes rencontrés par les clients ainsi que les clients qui vont quitter la sociétés... ca va mal! (supérieur hiérarchique qui communique des informations stressantes non appropriées dans le cas présent, car ce n'est pas une équipe commerciale. Sont-elles vraiment utiles pour les subordonnés? Cas vécu).

    Ce petit aparté pour préciser que conjointement à la non-communication, d'autres procédés sont également utilisés pour asseoir le pouvoir.

    Une communication saine
    Une communication saine, ce n'est pas communiquer à outrance (trop d'information tue l'information).
    Il va de soi que toute l'information ne doit pas être communiquée à tous les niveaux de la hiérarchie... certaines d'entre-elles ne relèvent que de la gestion.
    Par contre, il est raisonnable de fournir aux concernés les informations qui leurs sont relevantes.
    Ainsi, il se sentiront plus concernés / impliqués et certainement plus compris.
    S'ils n'ont pas le pouvoir de décision final, les subordonnés pourront faire part ouvertement de leurs expériences et idées (bonnes ou pas).
    Une communication saine et ouverte (sans rétention abusive) contribuera à maintenir une bonne et saine ambiance générale.
    Un manager communicant montre également l'exemple, ce qui promeut la communication au sein de l'équipe et forcement cela optimise le processus de production (que cela soit un service comptable, bureau d'ingénieur ou plateau de production)

    En guise de conclusion, il me faudra aussi envisager dans un autre article la situation des subordonnés non-communicants :-)

    mercredi 10 novembre 2010

    5000 pages consultées

    La nuit dernière, ce blog a passé le cap des 5000 consultations.
    En fin de compte, cela me fait plaisir de pouvoir partager les quelques connaissances accumulées.
    Cela me fait encore plus plaisir de constater qu'elles sont vraisemblablement appréciées et utiles.

    Ce n'est d'ailleurs pas tout, dans très peu de temps j'attendrai également la barre des 300 articles.

    Statistique Blogger du mois courant
    Les articles les plus populaires sont:

    Théorie des cordes


    La théorie des cordes (voir wikipédia) est propre au monde de la physique théorique.
    Cette théorie offre un "Univers Elégant" permettant de relier deux mondes de la physique théoriques totalement incompatible jusqu'alors.
    Il s'agit d'un côté de la théorie de la relativité de Einstein qui s'intéresse à l'infiniment grand (les univers) et de l'autre les théories Quantiques (Max Planclk) qui s'intéresse à l'infiniment petit (les atomes, particules, Quarks, etc).
    En effet, la théorie de la relativité ne peut pas s'appliquer aux interactions oeuvrant à l'échelle de l'infiniment petit... et inversement, les théories de l'infiniment petit (th. quantique) sont incompatibles avec ce que nous savons de l'infiniment grand (ex: les observations astronomique).
    Il faut avouer que cela est gênant, deux théories distinctes, parfaites dans leurs domaines respectifs mais sans aucun point de liaisons entre-elles.

    La théorie des cordes, qui est par ailleurs toujours en cours d'évolution, permet d'unifier ces théories.
    Elle offre des mécanismes théoriques pour passer d'un monde à l'autre. Mais cela réclame néanmoins un peu de gymnastique intellectuelle.

    Pour utiliser une méthaphore compréhensible, toutes les particules de l'univers pourraientt être représentées à l'aide de cordes vibrantes.
    Si l'on pouvait zoomer suffisamment sur un électron qui gravite autour de l'atome, on pourrait voir sa corde vibrer à une certaine fréquence.
    Si on pouvait la pincer, cette corde changerait de fréquence de vibration et l'on pourrait transformer l'électron en une autre particule comme un quark.
    Si on la repinçait encore une fois, on pourrait cette fois obtenir un photon, etc.

    Voici une série de vidéos de vulgarisation collectées sur la toile.
    Elle sont très instructives et offre également l'opportunité abordable de se familiariser avec le concept des univers à plus de 3 dimensions.
    Plus fort encore, on y présente aussi une métaphore introduisant le principe des dimensions supplémentaires que nous ne sommes pas humainement capable de percevoir.



    Sur Arte




    (Il manque juste un petit bout à la fin de ce film... et c'est bien dommage)



    mardi 9 novembre 2010

    Sync C# - Wait And Pulse - ProducerConsumerQueue non bloquant

    Qu'est-ce qu'une synchronisation bloquante
    Par exemple, lorsque l'on protège une section de code comme par exemple l'accès a une variable utilisée par deux threads, ont met en place une synchronisation bloquante.Un thread ne peut absolument pas accéder à la section critique (protégée par la section du lock) pendant qu'un autre thread accède à la section. Le thread ne pouvant pas accéder à la section critique est bloqué (c'est d'ailleurs sont état interne).
    Ce même cas de figure se présente également pour les threads partageant une même section critique, comme c'est le cas entre-autre pour les précédents exemples démontrant le fonctionnement interne d'une ProducerConsumerQueue (voir les articles Sync C# - ProducerConsumerQueue et Sync C# - Multi-Producer Multi-Consumer Queue).

    Le thread bloqué n'utilise plus de ressource CPU mais peut également être retiré de la pile d'exécution par le scheduler. Cette perte de temps inhérent aux opérations de scheduling/descheduling (context switching) peut devenir trop important si l'on est face à un système nécessitant une forte réactivité.
    C'est là qu'intervient Wait And Pulse.

    Description du pattern Wait And Pulse
    Wait And Pulse est une méthode de synchronisation non bloquante.
    Wait And Pulse est un pattern permettant de partager une sections critique (lock) entre deux ou plusieurs threads tout en évitant le context switching (scheduling/deschéduling).
    La section de lock est partagée (balancée) entre les threads à l'aide des instructions Monitor.Wait( LockingObject ) et Monitor.Pulse( LockingObject ).
    Pour fonctionner correctement, le pattern doit être scrupuleusement suivit... et la section critique doit impérativement commencé par un Wait.
    Losrque le wait est exécuté par un thread (le waiting thread) sur dans la section critique, le Framework libère le bloquage... ce qui permet à un autre thread d'acquérir (ou réacquérir) ce blocage jusqu'aà l'exécution d'un Pulse (lui c'est le pulsing thread).
    Donc, en pratique, le pulsing thread effectue ses traitements et fait un pulse.
    Lorsque le pulse est exécuté, le pulsing thread se bloque... libère le blocage pour le waiting thread.
    Le waiting thread réacquière le lock et effectue ses traitements... une fois fait, il réexécute un wait, ce qui libère le lock pour le pulsing thread.
    Le pulsing thread réacquière le lock et effectue ses traitements et puis fait un pulse... etc... etc... etc.

    Dans cette description, on remarque nettement que le Waiting thread et le Pulsing thread travaillent tous les deux en tandem. Et l'exécution balance d'un thread à l'autre.
    Si les explications manquent d'un peu de clarté, confrontez les au pseudo-code ci-dessous.

    Pseudo-code du pattern
    class WaitPulsedPattern {
        /* ... Déclaration privé variables protégées et partagées
          ... ex: une queue, un flag Go, une combinaison de flags, etc */
        private object locker = new object(); 
    
        public WaitPulsedPattern() { // CTor
             /* ... Démarrage des Waiter Thread (consumer)
               ... Exécute la méthode Worker()  */
        }
        
        public SomeProducer() {    
            /* ... méthode producer qui modifie la variable protégé
               ...    et fait le pulse */
        
            lock( locker ) {
                // ... modification des variables protégées
                Monitor.Pulse( locker ); 
            }
        }
    
        public void Worker() {
            while( true ) {
                lock( locker ) {
                    while( ! Variables_Partagées_Indique_Du_Travail )
                        Monitor.Wait( locker );            
                    CopieVariable = ... copier les informations du travail à faire ... 
                } // lock libéré  
                
                // Arrêter le thread de traitement?
                if( Conditions_D_arret )
                    return;
                
                // ... effectuer le travail ...
            }
        }
    }
    
    

    Wait And Pulse ProducerConsumerQueue 
    Voici une implémentation du pattern ProducerConsumerQueue (multi-consumer) utilisant Wait And Pulse.
    Fichier: Threading_ProducerConsumerQueue_WaitPulse.cs

    Quelques mots d'explication:
    • Les tâches sont empilées dans une queue (_taskQueue) protégé par l'objet de synchronisation _locker.
    • L'objet de synchronisation pour mettre en place la pattern Wait And Pulse.
    • Les threads de traitement (consumers) passe en Wait dès que la queue de traitement est vide.
    • Les threads de traitement terminent leurs processus dès qu'une tâche null est extraite de la queue (c'est l'exit condition des threads).
    • Les threads de traitement maintiennent le lock de façon aussi brève que possible.
      Il s'agit du temps entre l'acquisition lock (ou réacquisition du lock après un wait) ET le wait suivant ou la sortie du block de locking.
    • Les threads consummers (ceux qui font le traitement des tâches) sont créés dès l'instanciation de la classe. Cela assure toujours que le premier wait sera exécuté avant le premier pulse.
      Le premier thread acquière immédiatement le lock et exécute le wait (car la queue est vide).
      Ce qui à pour effet de relâcher le lock en attente d'un pulse dans le thread principal.
    • Le thread principal enqueue les tâches et utilise pulseAll pour signaler TOUS les consumers threads en attente.
    • Finalement, Dispose empile des nulls dans la queue (exit condition des consumer threads) et attends la fin de leur exécution.

    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    public class WaitPulseProducerConsumerQueue : IDisposable
    {
        private object _locker = new object();
        private Queue<string> _tasksQueue = new Queue<string>();
        private Thread[] consumerThreads;
        
        public WaitPulseProducerConsumerQueue( int ConsumerCount ) 
        {
            // Create and Fire Consumer Threads
            consumerThreads = new Thread[ConsumerCount];
            for( int i = 0; i < ConsumerCount; i++ )
                consumerThreads[i] = new Thread( new ThreadStart(ConsumeWorker) );
            // Wait/Pulse requires Wait to be executed first --> start the 
            //    threads now will ensure it.
            foreach( Thread th in consumerThreads )
                th.Start();
        }
        
        /// <summary>
        /// Consumer for the Queue. This will run into a thread
        /// </summary>
        public void ConsumeWorker() 
        {
            while( true ) {
                string task;
                lock( _locker ){
                    // If the queue is empty --> wait (will release the lock)
                    if( _tasksQueue.Count == 0 ) Monitor.Wait( _locker );
                    // Dequeue task & release the lock
                    task = _tasksQueue.Dequeue();
                }
                // Exit condition --> exit the thread
                if( task == null )
                    return;
                // process the task
                Console.WriteLine( string.Format( "Processing task {0}", task ) );
                // Mimic processing
                Thread.Sleep( TimeSpan.FromSeconds( 1 ) );
            }
        }
        
        public void Dispose() {
            // Inform threads to exit
            foreach( Thread th in consumerThreads ) EnqueueThreadExit();
            // Wait all thread to ends
            foreach( Thread th in consumerThreads ) th.Join();
        }
        
        /// <summary>
        /// Enqueue data + pulse worker
        /// </summary>
        /// <param name="sTask"></param>
        public void Enqueue( string sTask ) {
            // Wait to acquire the lock
            lock( _locker ) {
                // Enqueue data
                _tasksQueue.Enqueue( sTask );
                // release lock to worker (until worker Waits)
                Monitor.PulseAll( _locker );
            }
        }
        
        private void EnqueueThreadExit() 
        {
            Enqueue( null );
        }
    }
    public class MyClass
    {
        public static void RunSnippet()
        {
            const int NBR_CONSUMER_THREADS = 3;
            WaitPulseProducerConsumerQueue q = new WaitPulseProducerConsumerQueue( NBR_CONSUMER_THREADS );
            WL( "Enqueue data" );
            for( int i = 1; i<= 12; i++ )
                q.Enqueue( string.Format( "task {0}", i ) );
            
            WL( "Disposing queue (send exit signal + joining  consumer threads)" );
            q.Dispose(); // ensure worker threads Join
            
            WL( "Queue disposed" );
        }
        
        #region Helper methods
        ...
        #endregion
    }
    

    Résultats:
    Enqueue data
    Processing task task 1
    Disposing queue (send exit signal + joining  consumer threads)
    Processing task task 2
    Processing task task 3
    Processing task task 4
    Processing task task 5
    Processing task task 6
    Processing task task 7
    Processing task task 8
    Processing task task 9
    Processing task task 10
    Processing task task 11
    Processing task task 12
    Queue disposed
    Press any key to continue...
    

    jeudi 4 novembre 2010

    Mal de l'étain, la maladie de nos appareils électroniques

    L'étain
    L'étain (wikipédia) est un métal bon conducteur d'électricité, qui fond à une température de fusion à 232°C et qui a une grande affinité pour le cuivre.
    Ces propriétés font de l'étain le métal idéal pour souder les composants électroniques. Ont retrouve donc de l'étain dans tous nos appareils... de la télévision, gsm, ordinateur en passant par les pacemaker, missiles, satellites, etc.

    Le mal de l'étain
    Et bien, lorsque l'on utilise de l'étain sur du cuivre, une pression peu apparaitre sous la couche d'étain suite à la diffusion du Cuivre dans l'étain.
    Ce phénomène est encore assez mal connu (sur le plan scientifique) mais résulte en l'éjection de filament d'étain de quelques centaines de nanomètres et pouvant atteindre jusqu'à 1 centimètre (avec le temps).
    Ces mini "poils" d'étain peuvent apparaître dans une laps de temps variant de quelques jours à quelques semaines.
    Dans un monde ou la miniaturisation est tellement importante que l'on atteints les limites de la physique, un micro fil conducteur d'étain (un Whiskers) peu facilement créer un court-circuit.
    Si certains d'entre-eux ne sont pas graves, d'autres peuvent avoir des conséquences graves.
    Source: Environmental Friendly Soldering Technologies (via Google Images)


    Source: Aci - Electroplated Tin and Tin Whiskers in Lead Free Electronics (via Google Images)
    Découverte des whiskers
    Les Whiskers sont connus depuis 1948.
    C'est grâce à l'opérateur américain AT&T que nous n'en avons pas trop souffert jusqu'a maintenant.
    Lorsque les Whiskers ont étés identifiés, les laboratoires AT&T ont menés des expériences pendant une décennie pour associés l'étain à chacun des éléments chimiques.
    Le but était bien évidemment de tenir les Whiskers sous contrôle.
    C'est ainsi qu'on a découvert que d'excellents résultat étaient obtenu en mélangeant un peu de plomb.
    La recette reste encore aujourd'hui empirique car le phénomène physique n'est pas encore entièrement maitrisé. C'est ainsi que le dosage de plomb peut varier entre 1 et 40%... lorsqu'il pouvait encore être utilisé.

    L'interdiction du plomb
    Si les traveaux de AT&T ont apporter une certaine sérénité durant des décennies, c'est sans compter avec une directive européenne datant de 2006.
    A quelques exceptions près, cette directive interdit purement et simplement l'usage du plomb dans les équipements électroniques.
    Exceptions: pour les secteurs d'activités a haut risque comme par exemple les secteurs militaires, aéronautiques, médicales, nucléaire.  

    Autrement dit, les Whiskers sont libres de pousser à nouveau.
    Dans quelques années nous connaîtrons probablement une hécatombe dans l'ère de l'information.
    Entre appareils électroniques aux comportements imprévisibles à de simples pannes soudaines mais définitives l'électronique défaillante pourrait offrir quelques beaux cheveux blancs à l'humanité.
    Les années 2011 à 2015 risque de réserver bien des surprises.


    A quand les boîtes de vitesses subitement folles, ou les systèmes de freinages bourrés électroniques (ex: ABS) devenu subitement incontrôlable.
    Il y a quelques mois, une très importante firme japonaise n'a t'il pas rappelé des dizaines de milliers de véhicules pour des problèmes de pédale de freinage. Vraiment des problèmes de pédale de freinage ou officieusement d'électronique de freinage?
    Si l'informatique peut prévoir beaucoup de cas, elle peut difficilement se prémunir contre les conséquences physiques des whiskers (court-circuits, modification de la logique au point de vue électrique).
    Notre vie et notre sécurité de tous les jours est intiment lié à l'électronique, les voitures sont munies de véritables ordinateurs de bords, les systèmes ferroviaires et de guidage aérien reposent abondamment sur l'informatique.
    Combien de processus de productions ne dépendent-ils pas de système électronique-informatiques?
    Toute notre économie repose sur la gestion de l'information, qui repose elle même sur... l'électronique.
    Si les banques, les assurances, etc peuvent facilement faire face à des pannes ponctuelles, que se passera t'ils lorsque celles-ci s'enchaineront à grands régimes et de façon imprévisibles (chaotique)?

    Surveiller la présence du plomb
    Si le plomb est encore autorisé pour les secteurs à risques, il faut maintenant s'assurer que les sous-traitants l'utilisent bien.
    Il semblerait que certains sous-traitent aient déjà surfacturé des composants "plombés" qui étaient en réalité les mêmes composants que ceux réservés au secteur grand public.
    EDF aurait déjà procédé au re-travail et remplacement de plusieurs composants de ses centrales nucléaires. Certains satellites souffrent de pannes que l'on peut raisonnablement liées au Whiskers. Finalement, un rapport relatif à la défaillance d'un module de contrôle de la navette Endeavour révèlerait la présence de 100 à 300 millions de Whiskers. (source: Science & Vie, oct. 2010)

    Une vérité qui dérange
    Si le phénomène est relativement peu connu du grand public, il l'est déjà moins des électroniciens et des informaticiens ayant une certaine expérience.
    Il est en effet assez courant de rencontrer des whiskers sur du vieux matériel informatique.
    Source: article de Low End Mac
     

    Si le grand public n'en connais rien, c'est parce que ce sujet gênant n'est pas ébruité.

    Il faut dire qu'il y a de quoi! Que dirait le consommateur moyen si ont lui annonçait d'emblée que son nouvel achat à prix d'or ne survivrait peut-être pas 3 ans?
    Pensez à des achats tels que iPad, iPhone, des ordinateurs portables tels que HP Pavillon, ou  une super mega télé 3D à 2000 Euro, un super ensemble Home Cinéma, etc.
    Les whiskers et le marketing ne font pas bon ménage.

    En s'attardant un peu sur des caractéristiques techniques tel que le "Mean Time Before Failure".
    D'une façon générale le MTBF des différents composants atteints de nos jours des valeurs astronomiques... par contre la garantie dépasse rarement un an (deux au mieux). Pour les mécaniques c'est encore compréhensible, il y a une usure inhérente... mais pour de l'électronique pur.

    Sources:
    Une bonne partie des informations reprisent dans cet article proviennent du Science&Vie no 1117 d'octobre 2010. Article écrit par Vincent Nouyrigat.
    Les autres sources (ex: images) sont mentionnées directement dans l'article.

    lundi 1 novembre 2010

    Sync C# - Multi-Producer Multi-Consumer Queue

    L'article "Sync C# - ProducerConsumerQueue" décrivait et implémentait le pattern ProducerConsumerQueue (lecture recommandée pour la compréhension de cet article).

    L'article ici présent est un complément qui met en place une version plus avancée du pattern où il est possible:
    • D'avoir plusieurs producer threads (soit plusieurs threads ajoutant des tâches dans la queue de traitement).
    • Mais également d'avoir plusieurs consumer threads (soit plusieurs worker threads traitant les tâches en attente dans la queue de traitement).
    Exemple - Multiple Producer, Multiple Consumer
    Le fichier Threading_MultiProducerMultiConsumerQueue.cs contient un exemple où la queue (de la classe ProducerConsumerQueue) est alimentée par plusieurs threads et où les tâches traitées par plusieurs worker threads.
    Le nombre de worker threads (consumer) étant indiqué en paramètre lors de la création de la classe ProducerConsumerQueue.

    Quelques-mots d'explication:
    • Tout comme dans le précédent article, lorsque qu'un worker thread (consumer) n'a plus de tâche à traiter dans la queue, il passe en attente de signal/évènement.
    • Tout comme dans le précédent article, un WaitHandle est utilisé pour signaler qu'une tâche est en attente de traitement. Ce WaitHandle se nomme whNewTaskAvailable.
      Comme c'est un AutoResetEvent, un seul des worker threads en attente est alerté. Si une deuxième tache arrive rapidement dans la queue, le signal est relancé et sera (plus que probablement) pris en charge par un autre worker thread en attente.
    • Tout comme le précédent article, empiler une tâche NULL permet informe via la queue que le traitement est terminé.
      Cependant, il y a ici une différence notable:
      • A) Le worker thread qui recoit la tache NULL lève le signal whExitWorkerThreads et termine son exécution.
      • B) Les autres workers threads en attente de signal et recevant le signal whExitWorkerThreads terminent leur processus. 
    • Un ManualResetEvent (WaitHandle) est utiliser pour signaler aux worker threads d'arrêter le processus (et le traitement de la queue).
      Il s'agit ici d'un Reset Event de type manuel car tous les workers threads doivent pouvoir être signalés.
      En effet, un AutoResetEvent n'aurait permis de signaler qu'un seul worker thread à la fois (puisqu'il est resetté automatiquement à chaque fois).
    • Les workers threads utilisent l'instruction WaitHandle.WaitAny pour détecter le signal/évènement whNewTaskAvailable ou whExitWorkerThreads.

    Code du ProducerConsumerQueue
    Le code complet du snippet est disponible dans le fichier Threading_MultiProducerMultiConsumerQueue.cs
    public class ProducerConsumerQueue : IDisposable {
        // Set true to see additional synchronization message
        const bool _SHOW_DEBUG_ = true;
        // Tasks queue, enqueue a NULL to exit worker thread
        Queue<string> tasks = new Queue<string>(); 
        // Will signal worker thread that new Tasks are present.
        //   AutoResetEvent because only one thread can take the task
        EventWaitHandle whNewTaskAvailable = new AutoResetEvent(false);
        // Will signal the woker Threads to terminate the execution
        //   All threads must be signaled
        EventWaitHandle whExitWorkerThreads = new ManualResetEvent(false);
        Object locker = new Object();
        List<Thread> workers = new List<Thread>();
        
        /// <summary>
        /// protect CTor without arguments
        /// </summary>
        private ProducerConsumerQueue() 
        {
        }
        
        /// <summary>
        /// CTor. Start the worker thread
        /// </summary>
        /// <param name="NbrWorkerThreads">Number of consumer threads to starts</param>
        public ProducerConsumerQueue( int NbrWorkerThreads ) {
            if( NbrWorkerThreads <= 0 )
                throw new ArgumentOutOfRangeException("NbrWorkerThreads", NbrWorkerThreads, "Must be greater than 0" );
            foreach( int i in Enumerable.Range( 0, NbrWorkerThreads )) {
                if( _SHOW_DEBUG_ )
                    Console.WriteLine( String.Format( "Create Worker #{0}", i+1) );
                Thread worker = new Thread( DoWork );
                workers.Add( worker );
                worker.Start();
            }
        }
        
        /// <summary>
        /// Enqueue some work
        /// </summary>
        /// <param name="sTaskToPrint"></param>
        public void EnqueueTask( string sTaskToPrint ){
            lock( locker ) {
                tasks.Enqueue( sTaskToPrint );
                whNewTaskAvailable.Set(); // if worker was blocking (because no more work), signal that new work arrived.
            }    
        }
        
        /// <summary>
        /// Enqueue a NULL to inform the worker threads to Exit
        /// The whExitWorkerThreads is not signaled here, this ensure all the queued tasks
        /// to be processed 
        /// </summary>
        public void EnqueueExitThread() {
            EnqueueTask( null );
        }
        
        /// <summary>
        /// Dispose the Object
        /// </summary>
        public void Dispose() {
            // Signal the consumer to exit
            EnqueueExitThread();
            // Wait workers threads to finish
            foreach( Thread worker in workers )
                worker.Join();
            // Release OS ressource
            whNewTaskAvailable.Close();
            whExitWorkerThreads.Close();
        }
        
        /// <summary>
        /// Method that implement the Consummer
        /// </summary>
        public void DoWork(){
            while(true) {
                string task = null;
                bool waitSignalToContinue = false; // Consumer waits for signal (new item added) to continue to consume
                
                // Dequeue the task
                lock( locker ) {
                    if( tasks.Count == 0 ) {
                        // No more work, thread should wait
                        waitSignalToContinue = true;
                    }
                    else {
                        // Make a copy of the task
                        string temp = tasks.Dequeue();
                        if( temp != null ) task = String.Copy( temp  );
                    
                        // Null is used to signal Exit Worker Thread
                        if( task == null ) {
                            if( _SHOW_DEBUG_ )
                                Console.WriteLine( String.Format("Received null task, current thread {0} set ExitWorkerThread signal and terminates", Thread.CurrentThread.GetHashCode()) );
                            // Signal ALL the worker threads to exit now;
                            whExitWorkerThreads.Set();
                            return; // Exit current thread
                        }
                    }
                                
                }
    
                // Wait for signal must be performed OUTSIDE the lock !
                if( waitSignalToContinue ) {
                    // if no more task in the list 
                    //   --> Block the thread and wait signal for new job to do    (or Exit thread)
                    if( _SHOW_DEBUG_ )
                        Console.WriteLine( String.Format( "Thread {0} WaitAny", Thread.CurrentThread.GetHashCode()) );
                    int whIdx = WaitHandle.WaitAny( new WaitHandle[] { whNewTaskAvailable, whExitWorkerThreads } );
                    switch ( whIdx ) {
                        case 0 : // whNewTaskAvailable
                            if( _SHOW_DEBUG_ )
                                Console.WriteLine( String.Format( "Thread {0} Received NewTaskAvailable signal", Thread.CurrentThread.GetHashCode()) );
                            // New task to execute -> continue thread execution
                            break;
                        case 1 : // whExitWorkerThreads
                            if( _SHOW_DEBUG_ )
                                Console.WriteLine( String.Format( "Thread {0} Received ExitWorkerThread signal", Thread.CurrentThread.GetHashCode()) );
                            // Exit the worker thread
                            return;
                        default:
                            throw new Exception( String.Format("Unexpected whIdx {0} value", whIdx ) );
                    } 
                }
    
                
                // Execute the task
                //   - task may be null if the Queue is empty
                //   - An whNewTaskAvailable may also not be captured yet 
                if( task != null ){
                    Console.WriteLine( String.Format( "Worker Thread {0} Performing task: {1}", Thread.CurrentThread.GetHashCode(), task) );
                    Thread.Sleep( TimeSpan.FromMilliseconds(500) );
                }        
    
            }
        }
    }