{"id":3783,"date":"2019-11-30T15:53:25","date_gmt":"2019-11-30T15:53:25","guid":{"rendered":"http:\/\/www.colorwave.it\/blog\/?p=3783"},"modified":"2019-11-30T15:53:25","modified_gmt":"2019-11-30T15:53:25","slug":"creazione-di-classi-thread-in-colibri","status":"publish","type":"post","link":"https:\/\/www.colorwave.it\/blog\/framework\/creazione-di-classi-thread-in-colibri\/admin\/2019\/11\/","title":{"rendered":"Creazione di classi thread in Colibr\u00ec"},"content":{"rendered":"<p>Colibri contiene diverse classi e definizioni\u00a0 per la gestione dei thread;\u00a0 tutte le classi e strutture di gestione dei threads sono contenute nel namespace <strong>CLB::Threads<\/strong>, definito nella dll <strong>CLB_000.<\/strong><\/p>\n<p>In questo articolo vengono descritte le classi <strong>Thread_status\u00a0<\/strong> e <strong>CLB_thread.<\/strong><\/p>\n<p>La <strong>Thread_status <\/strong>fornisce funzioni per la gestione di liste di eventi,\u00a0 semafori e mutex visibili\u00a0 all\u2019interno e\/o all\u2019esterno del thread; in pratica costituisce un\u2019interfaccia di sincronizzazione fra i diversi thread, ed \u00e8 programmabile per una gestione molto complessa degli stessi.<\/p>\n<p>La <strong>CLB_Thread <\/strong>deriva da Thread_status e mette a disposizione un insieme di funzioni e metodi per gestire lo stato del thread, la sua sospensione\/cancellazione, il passaggio di parametri fra thread, la visualizzazione dello stato di avanzamento ecc..<\/p>\n<p>Per concludere questa breve introduzione:<\/p>\n<p><strong>Thread_status<\/strong> \u00e8 <em>l\u2019interfaccia<\/em> di <strong>CLB_Thread<\/strong> che gestisce gli eventi,i semafori e mutex;<\/p>\n<p><strong>CLB_Thread<\/strong> \u00e8 la classe dalla quale derivano i thread usati nel framework Colibr\u00ec.<\/p>\n<p>Questo articolo affronta tre argomenti:<\/p>\n<ul>\n<li style=\"text-align: left;\">Thread_status<\/li>\n<li style=\"text-align: left;\">CLB_thread<\/li>\n<li style=\"text-align: left;\">Costruzione di thread derivati da CLB_Thread<\/li>\n<\/ul>\n<h3>Alcune precisazioni prima di continuare..<\/h3>\n<p>Le classi di seguito descritte sono utilizzate nella<strong> programmazione concorrente<\/strong>, da non confondere con la<strong> programmazione parallela, <\/strong>alla quale abbiamo fatto riferimento descrivendo le classi del <a href=\"https:\/\/www.colorwave.it\/blog\/heterogeneus-computing\/terminologia-opencl\/admin\/2017\/12\/\" target=\"_blank\" rel=\"noopener noreferrer\">namespace OPCL<\/a><\/p>\n<p>La comprensione degli oggetti descritti in questo articolo presuppone che il lettore abbia sufficiente conoscenza dei seguenti concetti usati in programmazione concorrente: Mutex, Semafori ed\u00a0 Eventi.<\/p>\n<p>&nbsp;<\/p>\n<!--nextpage-->\n<p>La classe permette la gestione di eventi e del loro stato.<\/p>\n<h3>Eventi<a id=\"eventi\"><\/a><\/h3>\n<p><span data-ttu-id=\"b744e-123\">Gli eventi sono utili quando un thread deve essere in grado di stabilire quando eseguire la relativa attivit\u00e0.<\/span>\u00a0<span data-ttu-id=\"b744e-124\">Ad esempio, un thread che trasferisce dati ad una stampante deve ricevere una notifica quando sono disponibili nuovi dati. La classe Thread_status fornisce un&#8217;interfaccia per gestire un insieme di eventi, permettendo la loro attivazione, disattivazione e verifica dello stato. Gli eventi sono gestiti a livello del sistema operativo e possono essere testati all&#8217;interno dei thread per gestire il flusso dell&#8217;elaborazione. Ciascun oggetto di tipo Thread_status gestisce un insieme di MAX_EVENTS\u00a0 eventi attivabili, ciascuno individuato da un valore HEVENT ,\u00a0<\/span><\/p>\n<pre class=\"lang:default decode:true\">#define MAX_EVENTS 32\r\n#define HEVENT  int<\/pre>\n<p>HEVENT \u00e8 un valore compreso fra 1 e MAX_EVENTS.\u00a0 I valori compresi fra 1 e (EV_USER-1) sono riservati per gestire eventi standard nella gestione dei thread di Colibr\u00ec. Attualmente sono definiti i seguenti codici, relativi allo stato dei thread derivati da CLB_thread:<\/p>\n<pre class=\"lang:default decode:true\">\t        \/**  codice evento start thread\r\n\t\t*\/\r\n\t\t#define EV_START\t1\r\n\r\n\t\t\/**  codice evento fine thread\r\n\t\t*\/\r\n\t\t#define EV_END\t\t2\r\n\r\n\t\t\/** codice evento termina thread\r\n\t\t*\/\r\n\t\t#define EV_EXIT\t\t3\r\n\r\n\t\t\/** codice evento stop da esterno del thread\r\n\t\t*\/\r\n\t\t#define EV_STOPPED\t4\r\n\r\n\r\n\t\t\/** codice iniziale evento utente\r\n\t\t*\/\r\n\t\t#define EV_USER\t10<\/pre>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignnone\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <strong>Nota: <\/strong><span style=\"color: #008080;\">istanze diverse delle <em>Thread_status<\/em> individuano con lo stesso valore\u00a0 HEVENT eventi distinti, caratteristici del thread considerato:\u00a0 ad esempio, EV_START identifica l&#8217;evento di lancio dell&#8217;esecuzione di un thread specifico; Inoltre, ciascun thread pu\u00f2 gestire eventi specifici definiti dal programmatore, ad esempio un evento che indica la terminazione di un ciclo di trasferimento di dati in un particolare thread potrebbe essere definito come segue:<\/span><\/p>\n<pre class=\"lang:default decode:true\">#define EV_END_MY_TRANSFER  EV_USER+3<\/pre>\n<p>notare che la definizione usa un id nella zona di valori &gt;=EV_USER.<\/p>\n<p>Analizziamo ora in dettaglio le funzioni e metodi della classe:<\/p>\n<pre class=\"lang:default decode:true\">\t\tclass AFX_EXT_CLASS Thread_status\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tThread_status();\r\n\t\t\tvirtual ~Thread_status();\r\n\r\n\t\t\tvoid Lock();\r\n\t\t\tvoid UnLock();\r\n\r\n\t\t\tvoid WaitEvent(HEVENT ev_code);\r\n\t\t\tvoid SetEvent(HEVENT ev_code);\r\n\r\n\t\t\tbool Verified(HEVENT ev_code);\r\n\t\t\tbool NotVerified(HEVENT ev_code);\r\n\r\n\t\t\tvoid Init();\r\n\r\n\t\t\tbool  GetStatus(HEVENT ev_code);\r\n\r\n\t\t\tvoid SetStatus(HEVENT ev_code, int value = 1);\r\n\r\n\t\t\tvoid StopTask();\r\n\r\n\t\t\tstatic void SigStart(char *file, char *function);\r\n\t\t\tstatic void SigEnd(char *file, char *function);\r\n\t\t\tstatic void  Dump(STRING filename);\r\n\r\n\t\t\t__use_private_struct\r\n\t\t};\r\n\r\n<\/pre>\n<h3><strong>SetEvent(HEVENT ev_code)<\/strong><\/h3>\n<p>Imposta lo stato dell&#8217;evento <strong>ev_code<\/strong> su segnalato, rilasciando eventuali thread in attesa. Cli eventi gestiti possono essere di tipo automatico o manuale (<a href=\"https:\/\/docs.microsoft.com\/it-it\/cpp\/mfc\/reference\/cevent-class?view=vs-2019#setevent\" target=\"_blank\" rel=\"noopener noreferrer\">vedi la classe CEvent<\/a>). in Thread_status gli eventi gestiti sono tutti automatici. Un evento automatico ritorna automaticamente a uno stato non segnalato (non disponibile) dopo che \u00e8 stato rilasciato almeno un thread.<\/p>\n<h3><strong>WaitEvent(HEVENT ev_code)<\/strong><\/h3>\n<p>Pone il thread in uno stato di attesa della segnalazione dell&#8217;evento ev_code; la funzione ritorna quando l&#8217;evento si \u00e8 verificato. Le funzioni SetEvent e WaitEvent sono usate all&#8217;interno delle due macro _EWAIT ed _ESIG sono usate internamente al codice dei thread per verificare lo stato degli eventi.<\/p>\n<h3><strong> bool Verified(HEVENT ev_code)<\/strong><\/h3>\n<p>Ritorna true se l&#8217;evento si \u00e8 verificato. E&#8217; utilizzato per verificare lo stato di un evento ma,\u00a0 a differenza di WaitEvent, non rimane in attesa della verifica (segnalazione)<\/p>\n<h3><strong> bool NotVerified(HEVENT ev_code)<\/strong><\/h3>\n<p>Ritorna true se l&#8217;evento non si \u00e8 verificato (ancora verificato). Il controllo dello stato dell&#8217;evento \u00e8, come Verified, immediato. Pu\u00f2 come Verified essere utilizzato in un Loop di attesa (vedremo in seguito alcuni esempi).<\/p>\n<h3><strong> void Init()<\/strong><\/h3>\n<p>Azzera tutti i semafori e gli eventi gestiti dalla classe. La funzione\u00a0 \u00e8 usata intervnamente nella inizializzazione della classa CLB_threads. Non deve essere usata in contesti diversi.<\/p>\n<h3><strong>bool GetStatus(HEVENT ev_code)<\/strong><\/h3>\n<p>Ad ogni evento \u00e8 associato uno bit interno che viene alzato quando l&#8217;evento si verifica, indipendentemente dalla cattura dello stesso (ved WaitEvent, ad esempio);<\/p>\n<p>ad esempio la GetStatus(EV_START) rimanda true se il thread \u00e8 stato attivato (lanciato), anche se si trova in uno stato di wait..<\/p>\n<h3><strong> void SetStatus(HEVENT ev_code, int value = 1)<\/strong><\/h3>\n<p>La funzione \u00e8 usata per segnalare lo stato di un evento attivato,\u00a0 e serve per testare dall&#8217;esterno che l&#8217;evento sia stato alzato almeno una volta. Non approfondiremo per ora le due funzioni GetStatue\u00a0 e SetStatus, segnalando che comunque devono essere considerate obsolete e saranno rimosse in una prossima revisione della libreria<\/p>\n<h3><strong>void Stop_thread()<\/strong><\/h3>\n<p>Ricordiamo che la classe\u00a0 <em>Thread_status<\/em> \u00e8 l&#8217;interfaccia di gestione di eventi ereditata dalla classe <em>CLB_thread<\/em><\/p>\n<p>Stop_thread \u00e8 una\u00a0 funzione che blocca l&#8217;esecuzione del thread\u00a0 ed attende che lo stesso Venga terminato (cio\u00e8 che si verifichi l&#8217;evento EV_END). Per le modalit\u00e0 di definizione dei thread di Colibri,\u00a0 la terminazione del CLB_thread di appartenenza \u00e8 certamente effettuata, eseguendo automaticamente tutte le funzionalit\u00e0 di rilascio degli oggetti e\u00a0 memoria usati internamente al thread stesso.<\/p>\n<p>nel seguito di questo articolo faremo un esempio di come viene utilizzata questa funzione.<\/p>\n<h3><strong>Funzioni di debug\u00a0<\/strong><\/h3>\n<p>Le due funzioni\u00a0 <strong>SigStart(..) <\/strong>e <strong>SigEnd(..)<\/strong> sono utilizzabili\u00a0 per monitorare lo stato di attivit\u00e0 dei thread\u00a0 nell&#8217;analisi della loro efficienza. Per ora non ne forniamo alcuna descrizione (lo faremo in un successivo articolo).<\/p>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <strong>Nota: <\/strong><span style=\"color: #008080;\">Quasi mai avremo la necessit\u00e0 di accedere direttamente all&#8217;interfaccia Thread_status; l&#8217;accesso alle sue funzionalit\u00e0 \u00e8 sempre fatto attraverso i comandi del linguaggio CLB_lang del framework di Colibr\u00ec.<\/span><\/p>\n<p><!--nextpage--><strong>CLB_thread<\/strong> \u00e8 la classe base dei thread costruiti mediante il framework di Colibr\u00ec. Eredita la classe Thread_status, che utilizza come interfaccia di gestione degli eventi e stati del thread. Le classi derivate sono costruite utilizzando un insieme di macro che semplificano la gestione interna,\u00a0 standardizzando i processi di interruzione dall&#8217;esterno del thread, la richiesta di sospensione o di terminazione, lo stato di waiting (attesa di eventi esterni), il passaggio on-fly di parametri ecc.<\/p>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/><\/p>\n<p><span style=\"color: #008080;\">Le classi CLB_thread non appaiono come threads direttamente eseguibili, ma nascondono al loro interno, come avremo occasione di mostrare uno o pi\u00f9 thread eseguibili, la cui gestione \u00e8 fatta dalla classe stessa. La distruzione (rilascio) della classe automaticamente comporter\u00e0\u00a0 la chiusura del thread\/threads in esecuzione al loro interno. I thread\u00a0 interni sono scritti utilizzando macro di CLB_lang: questo garantisce l&#8217;assoluta trasparenza nel controllo del loro funzionamento interno, con test automatici sullo stato degli eventi correlati alla loro esecuzione.<\/span><\/p>\n<pre class=\"lang:default decode:true\" title=\"La Classe CLB_thread\">class AFX_EXT_CLASS CLB_thread : public Thread_status\r\n{\r\npublic:\r\n   CLB_thread(void);\r\n   ~CLB_thread(void);\r\n   \r\n    void Set_loop_interval(int minv, int maxv);\r\n    void Get_loop_interval(int *minv, int *maxv);\r\n\r\n    bool Set_argument_list(__arg_value pars, ...);\r\n    bool Push_argument(__arg_value arg);\r\n    __arg_value Pop_argument();\r\n\r\n    ARGPTR *GetArgumentList();\r\n\r\n    float Perc();\r\n    void SetPerc(float perc);\r\n    \r\n\r\n    virtual bool Start();\r\n    virtual bool Suspend(); \r\n    virtual bool Stop();\r\n    bool Terminated();\r\n\r\n   __use_private_struct\r\n};\r\n<\/pre>\n<p>Non tutte le funzioni di questa classe hanno utilit\u00e0 generale, ad esempio le due funzioni Set_loop_interval()\u00a0 e Get_loop_interval() sono usate in casi particolari per estrarre i parametri di ciclo di elaborazione. Alcune funzioni come Perc() e SetPerc() sono usate per leggere ed assegnare una percentuale di esecuzione attuale del thread, che possono essere ricevute ad esempio dalle classi che ne visualizzano lo stato.<\/p>\n<p>LA funzionE virtuali <em><span style=\"color: #0000ff;\">Start<\/span> deve essere riscritta per ciascuna classe derivata da\u00a0 CLB_thread<\/em><\/p>\n<p>Le funzioni virtuali\u00a0<em><span style=\"color: #0000ff;\"> Suspend<\/span> e <span style=\"color: #0000ff;\">Stop<\/span> <span style=\"color: #008080;\">possono <\/span><\/em>essere riscritte per ciascuna classe derivata da\u00a0 CLB_thread, per effettuare operazioni specifiche prima o dopo la richiesta di sospensione, o stop. In ogni caso devono al loro interno richiamare la <em>CLB_thread::Stop o CLB_thread::Suspend<\/em><\/p>\n<h3><strong> Start()<\/strong><\/h3>\n<p>La funzione Start()\u00a0 \u00e8 virtuale, cio\u00e8 deve essere riscritta per ciascuna classe thread derivata, ed \u00e8 la funzione di esecuzione del thread.\u00a0 Al suo interno far\u00e0 riferimento, come vedremo nell&#8217;esempio alla definizione del thread\/threads gestito dalla classe.<\/p>\n<h3><strong>Suspend()<\/strong><\/h3>\n<p>La funzione Suspend() sospende l&#8217;esecuzione del thread fino a chiusura o riattivazione dello stesso.<\/p>\n<h3><strong>Stop()<\/strong><\/h3>\n<p>La funzione Stop() blocca l&#8217;esecuzione del thred ed esce quando l&#8217;evento EV_END \u00e8 stato effettivamente alzato. Internamente la CLB_event::Stop() richiama la funzione Thread_status::Stop_thread() che gestisce la sequenza di eventi per il blocco del thread.<\/p>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <strong>Nota:\u00a0 <\/strong><span style=\"color: #008080;\">Le classi derivate da CLB_thread che avessero la necessit\u00e0 di riscrittura della Stop() e Suspend() , ad esempio per effettuare particolari azioni prima o dopo, comunque dovranno richiamare la CLB_thread_Stop() o CLB_thread_Suspend() prima di uscire; Di seguito \u00e8 riportato un esempio di funzioni Stop e Suspendi di una classe<\/span><\/p>\n<pre class=\"lang:default decode:true\">class my_clb_thread : public CLB_thread\r\n{\r\n\r\n....\r\n\r\nbool Stop()\r\n{\r\n  ....  to do before stop..\r\n  CLB_thread::Stop()\r\n  ...   to do after stop ..\r\n}\r\n\r\nbool Suspend()\r\n{\r\n  ....  to do before suspend..\r\n  CLB_thread::Supend()\r\n  ...   to do after suspend..\r\n}\r\n\r\n\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h3><strong>Terminated()<\/strong><\/h3>\n<p>La funzione rimanda true se il thread ha terminato la sua funzione ( vedi Start())<\/p>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignnone\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <strong>Nota<span style=\"color: #008080;\">: <\/span><\/strong><span style=\"color: #008080;\">Le classi\u00a0 derivate da CLB_thread non vengono automaticamente eliminate alla chiusura del thread in esecuzione; pertanto possono essere riattivate o distrutte su richiesta del programmatore<\/span><\/p>\n<p><!--nextpage-->La classe CLB_thread contiene un insieme di funzioni per trasferire parametri al thread in esecuzione; <span style=\"color: #008000;\"><em>In questo articolo i termini<\/em> argomento e parametro identificano lo stesso oggetto,<\/span> cio\u00e8 un generico valore passato ad una funzione per la sua esecuzione. Per mantenere la genericit\u00e0 della funzione, i parametri sono passati al thread in modo molto simile alla sequenza di comandi utilizzata per <a href=\"https:\/\/www.colorwave.it\/blog\/framework\/clb_messenger-la-nuova-interfaccia-di-messaggistica-fra-oggetti\/admin\/2019\/11\/\" target=\"_blank\" rel=\"noopener noreferrer\">CLB_messenger<\/a> (vedi<a href=\"https:\/\/www.colorwave.it\/blog\/framework\/clb_messenger-la-nuova-interfaccia-di-messaggistica-fra-oggetti\/admin\/2019\/11\/\" target=\"_blank\" rel=\"noopener noreferrer\"> questo articolo<\/a> e <a href=\"https:\/\/www.colorwave.it\/blog\/widgets\/messages\/le-macro-di-gestione-dei-messaggi-fra-oggetti\/admin\/2019\/11\/\" target=\"_blank\" rel=\"noopener noreferrer\">quest&#8217;altro<\/a>) utilizzando la funzione\u00a0 Set_argument_list(..) che trasmette una lista variadic di valori __arg_value.<\/p>\n<p>Un altro metodo di passare i parametri \u00e8 quello di usare la funzione Push_argument(..) che permette il trasferimento sequenziale di un numero qualunque di parametri alla classe CLB_thread.<\/p>\n<p>Il thread in esecuzione lanciato con la funzione Start() viene definito attraverso delle macro di CLB_lang e, fra queste, una macro, la __thr_pop_p(..) permette l&#8217;estrazione sequenziale dei parametri.<\/p>\n<p><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignnone\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <strong>Nota<span style=\"color: #008080;\">: <\/span><\/strong><span style=\"color: #008080;\">il tipo di parametri e la loro sequenza devono essere identici in ingresso ed estrazione degli stessi; i parametri, come si osserva, sono sempre di tipo <\/span><span style=\"color: #008080;\">__arg_value (cio\u00e8 void *), mentre la funzione thread li convertir\u00e0 nel tipo atteso mediante la macro __thr_pop_p.<\/span><\/p>\n<h3>bool Set_argument_list(__arg_value pars, &#8230;)<\/h3>\n<p>La funzione permette di trasferire in un solo comando la sequenza dei parametri necessari al thread. Ad esempio, il thread che calcola una variante colore \u00e8 inizializzato in questo modo:<\/p>\n<pre class=\"lang:default decode:true\">...\r\n...\r\n\r\n\t\tTHREAD_CALC_CWY *thr= new THREAD_CALC_CWY;\r\n\r\n\t\tthr-&gt;SetCalculationModel(_$str-&gt;ovl_model);\r\n\r\n\t\tthr-&gt;Set_argument_list\r\n\t\t(\r\n\t\t\t_$str-&gt;SPT,\t\t\t\/\/ spettri tagli dei colori sui quadri\r\n\t\t\ttbl,\t\t\t\t\/\/ tabella delle concentrazioni\r\n\t\t\t&amp;_$str-&gt;nchn,\t\t\/\/ numero di quadri presenti\r\n\t\t\tCHNCOL,\t\t\t\t\/\/ lista dei colori canale (per ricavare l'ordine di stampa dei quadri)\r\n\t\t\tCRGB,\t\t\t\t\/\/ tabella rgb da inizializzare\r\n\t\t\t_$str-&gt;visibility, \t\/\/ vettore delle visibilit\u00e0 canali\r\n\r\n\t\t\t(ref_tbl ? CREF : 0),\/\/ calcola la tabella delle riflettanze\r\n\t\t\t&amp;_$str-&gt;ovl_model,\t\/\/ modello calcolo sovrapposizioni\r\n\t\t\tcoverage,\t\t\t\/\/ vettore coprenze coloi canali\r\n\t\t\t&amp;model,\t\t\t\t\/\/ modello gray, dithering etc\r\n\r\n\t\t\t(_$str-&gt;background.IsVisible() ? _$str-&gt;background.GetColor(): 0), \t\/\/ uso del millepunti, se definito\r\n\t\t\t_$end\r\n\t\t);\r\n\r\n...\r\n...<\/pre>\n<p><strong><img decoding=\"async\" data-attachment-id=\"3296\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3296\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-orig-size=\"48,48\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?fit=48%2C48&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"wp-image-3296 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-107.png?resize=23%2C24&#038;ssl=1\" alt=\"\" width=\"23\" height=\"24\" data-recalc-dims=\"1\" \/> <span style=\"color: #ff0000;\">Importante<\/span><\/strong><span style=\"color: #ff0000;\">: <\/span><strong><span style=\"color: #ff0000;\">L&#8217;ultimo argomento passato alla funzione \u00e8 la macro _$end,<\/span><\/strong><\/p>\n<p>&nbsp;<\/p>\n<h3>bool Push_argument(__arg_value arg)<\/h3>\n<p>Immette un argomento nella lista di quelli necessari all&#8217;esecuzione del thread; La sequenza degli inserimenti mediante questa funzione sar\u00e0 ovviamente identica a quella definita attraverso la\u00a0 <em><span style=\"color: #008000;\">Set_argument_list . <\/span><\/em>\u00a0due metodi sono equivalenti, la scelta del metodo utilizzato \u00e8 generalmente\u00a0 in funzione della chiarezza espositiva nella scrittura del programma.<\/p>\n<h3>ARGPTR *Get_argument_list()<\/h3>\n<p>La funzione rimanda la lista ordinata degli argomenti inseriti con le due funzioni precedenti.\u00a0 La Get_argument_list() \u00e8 utilizzata per lo pi\u00f9 dalle macro di definizione del thread, pertanto non c&#8217;\u00e8 alcuna necessit\u00e0 di un uso diretto.<\/p>\n<h3>__arg_value Pop_argument()<\/h3>\n<p>Inserisce sequenzialmente un parametro nella lista di quelli trasferiti al CLB_thread; \u00e8 usata internamente dalla macro __thr_push_p usata nel corpo della macro che alloca i thread, che sar\u00e0 descritta fra poco. pertanto non c&#8217;\u00e8 alcuna necessit\u00e0 di un uso diretto.<\/p>\n<h3>__arg_value Push_argument()<\/h3>\n<p>Estrae sequenzialmente un parametro dalla lista di quelli trasferiti al CLB_thread; \u00e8 usata internamente alla macro <span style=\"color: #008080;\">__thr_pop\u00a0\u00a0<\/span>richiamata nel corpo della funzione thread, che sar\u00e0 descritta fra poco. pertanto non c&#8217;\u00e8 alcuna necessit\u00e0 di un uso diretto.<!--nextpage--><\/p>\n<p>In quest&#8217;ultima parte dell&#8217;articolo introdurremo un insieme di macro, appartenenti a CLB_lang, che semplificano la gestione ed attivazione dei thread associati alle classi CLB_thread. Abbiamo gi\u00e0 osservato che le classi CLB_thread non espongono direttamente la dichiarazione delle funzioni thread eseguite, ma solo un insieme di funzioni e macro, valide per qualunque classe derivata, che ne permettono la gestione in termini di lancio, sospensione, interruzione e stato di attivit\u00e0. Vediamo con un esempio reale, scritto all&#8217;interno di Colibri: la classe\u00a0 <span style=\"color: #008000;\">THREAD_calc_dither<\/span>.<\/p>\n<p><strong><span style=\"color: #008000;\">THREAD_calc_dither<\/span><\/strong> \u00e8 una classe che riceve in ingresso un file da retinare ed altri parametri utilizzati per la retinatura, eseguendo\u00a0 internamente un thread.\u00a0 La procedura chiamante, a fine esecuzione potr\u00e0 richiedere il file retinato attraverso la funzione Get_dithered_map(). . Non discutiamo del risultato del procedimento,\u00a0 ma solo sul modo in cui i parametri sono passati alla classe <em><span style=\"color: #008000;\">THREAD_calc_dither <\/span><\/em><span style=\"color: #808080;\">e come internamente vengono usati.<\/span><\/p>\n<p>Di seguito la dichiarazione dell classe:<\/p>\n<pre class=\"lang:default decode:true\">class AFX_EXT_CLASS THREAD_calc_dither   : public CLB_thread\r\n\t{\r\n\tpublic:\r\n\tTHREAD_calc_dither(void);\r\n\t~THREAD_calc_dither(void);\r\n\r\n\tvirtual bool Start();\r\n\r\n\tIMG_FBUF *Get_dithered_map();\t\r\n\r\n\t__use_private_struct\r\n};\r\n<\/pre>\n<p>Come si osserva, la classe espone solo due funzioni:<\/p>\n<ul>\n<li>Start() usata per lanciare il thread interno<\/li>\n<li>Get_dithered_map() per estrarre il risultato a fine processo<\/li>\n<\/ul>\n<p>La Start \u00e8 la riscrittura della classe virtuale CLB_Thread, che, come abbiamo scritto \u00e8 necessario riscrivere per le classi derivate;<\/p>\n<p>La classe THREAD_calc_dither \u00e8 usata in una funzione che esegue la trasformazione di un insieme di canali graytone in canali retinati:<\/p>\n<pre class=\"lang:default decode:true\">\tbool CREATE_DITHERING(CLASS_STR)\r\n\t{\r\n\t\t__cursor_wait\t\/\/ visualizza il cursore di waiting\r\n\r\n\t\tint n=_$str-&gt;img-&gt;GetChannelList()-&gt;Num();\r\n\t\tDOC_AREA *ar=$obj-&gt;GetSize();\r\n\r\n\t\t\r\n\t\t\/\/ usa le curve della variante attiva;\r\n\t\t\/\/\r\n\t\tif (_$str-&gt;use_curve) {\r\n\t\t\tCOLORWAY *cwy=_$str-&gt;img-&gt;GetColorwayProject()-&gt;GetColorway();\r\n\t\t\tcwy-&gt;GetDensityCurves(_$str-&gt;_DENSITY);\r\n\t\t}\r\n\r\n                _$str-&gt;threads= new CLB_thread_list; \r\n\t\tfor (int i=0;i&lt;n;i++) {\r\n\r\n\t\t\t__thread_new(THREAD_calc_dither);\r\n\r\n\t\t\t__thr_push_p(_$str-&gt;img-&gt;GetChannelList()-&gt;GetChannel(i))\t\/\/ canale \r\n\t\t\t__thr_push_p(_$str-&gt;dth[i])\t\t\t\t\t\t\t\t\t\/\/ dithering da usare\r\n\t\t\t__thr_push_p(&amp;ar-&gt;dx)\t\t\t\t\t\t\t\t\t\t\/\/ dimensioni mappa generata\r\n\t\t\t__thr_push_p(&amp;ar-&gt;dy)\r\n\t\t\tif (_$str-&gt;use_curve)\r\n\t\t\t\t__thr_push_p(_$str-&gt;_DENSITY[i])\t\t\t\t\t\t\t\/\/ curva di correzione densit\u00e0\r\n\t\t\telse __thr_push_p(0);\r\n\r\n\t\t\t_$str-&gt;threads-&gt;Add(_thr);\r\n\t\t}\r\n\t\t_$str-&gt;threads-&gt;UseDisplayProgressWindow(__translate(\"Create Screens channels\"),\r\n\t\t\t\t\t\t\t__translate(\" Wait: the program is building dithered channels..\"));\r\n\t\treturn _$str-&gt;threads-&gt;Start();\r\n\t}\r\n<\/pre>\n<p><strong><img decoding=\"async\" data-attachment-id=\"3285\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3285\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-orig-size=\"24,24\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"alignleft size-full wp-image-3285\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?resize=24%2C24&#038;ssl=1\" alt=\"\" width=\"24\" height=\"24\" data-recalc-dims=\"1\" \/>Prima osservazione:<\/strong> Come si pu\u00f2 intuire dalla lettura del codice, ciascun canale graytone \u00e8 retinatato da un thread; per fare questo si allocano\u00a0 tanti thread quanti sono i canali , aggiungendoli come thread figli ad un gestore della lista: CLB_thread_list :<\/p>\n<pre class=\"lang:default decode:true\"> _$str-&gt;threads= new CLB_thread_list;<\/pre>\n<p>CLB_thread_list ha il compito di generare un thread che rimane in attesa che tutti i thread figli siano correttamente terminati.<\/p>\n<p><a id=\"ciclo_di_thread_di_retinatura\"><\/a>Il ciclo di for(..) che segue genera ed assegna i parametri a ciascun THREAD_calc_dither, aggiungendolo al CLB_thread_list<\/p>\n<pre class=\"lang:default decode:true\">for (int i=0;i&lt;n;i++) {\r\n\r\n\t\t\t__thread_new(THREAD_calc_dither);\r\n\r\n\t\t\t__thr_push_p(_$str-&gt;img-&gt;GetChannelList()-&gt;GetChannel(i))\t\/\/ canale \r\n\t\t\t__thr_push_p(_$str-&gt;dth[i])\t\t\t\t\t\t\t\t\t\/\/ dithering da usare\r\n\t\t\t__thr_push_p(&amp;ar-&gt;dx)\t\t\t\t\t\t\t\t\t\t\/\/ dimensioni mappa generata\r\n\t\t\t__thr_push_p(&amp;ar-&gt;dy)\r\n\t\t\tif (_$str-&gt;use_curve)\r\n\t\t\t\t__thr_push_p(_$str-&gt;_DENSITY[i])\t\t\t\t\t\t\t\/\/ curva di correzione densit\u00e0\r\n\t\t\telse __thr_push_p(0);\r\n\r\n\t\t\t_$str-&gt;threads-&gt;Add(_thr);\r\n\t\t}<\/pre>\n<p>Per farlo utilizza due macro di CLB_lang;<\/p>\n<h4>_thread_new :<\/h4>\n<p>genera un&#8217;istanza del tipo passato (THREAD_calc_dither).\u00a0 il nome dell&#8217;istanza \u00e8, convenzionalmente <strong><span style=\"color: #008000;\">_thr <\/span><\/strong>\u00a0per semplificare la scrittura del codice successivo.<\/p>\n<h4>__thr_push_p :<\/h4>\n<p>inserisce sequenzialmente i parametri utilizzati dalla classe per l&#8217;esecuzione dei calcoli.\u00a0<em> argomento della macro \u00e8\u00a0 sempre un puntatore;<\/em> la macro \u00e8 richiamata tante volte quanti sono gli argomenti da passare alla THREAD_calc_dither.<\/p>\n<p>Quindi l&#8217;istanza _thread viene aggiunta alla lista di esecuzione.<\/p>\n<pre class=\"lang:default decode:true \">..\r\n_$str-&gt;threads-&gt;Add(_thr);\r\n..<\/pre>\n<p>A terminazione del\u00a0 ciclo di costruzione, viene chiamata una funzione di CLB_thread_list che inizializza una finestra di visualizzazione dello stato di esecuzione dei thread; vengono assegnate due stringhe di visualizzazione<\/p>\n<pre class=\"lang:default decode:true\">_$str-&gt;threads-&gt;UseDisplayProgressWindow(__translate(\"Create Screens channels\"),\r\n\t\t\t\t\t\t\t__translate(\" Wait: the program is building dithered channels..\"));<\/pre>\n<p>La finestra (modale) verr\u00e0 visualizzata durante l&#8217;esecuzione del\/dei thread<\/p>\n<pre class=\"lang:default decode:true \">return _$str-&gt;threads-&gt;Start();<\/pre>\n<p><strong><img decoding=\"async\" data-attachment-id=\"3285\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3285\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-orig-size=\"24,24\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"alignleft size-full wp-image-3285\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?resize=24%2C24&#038;ssl=1\" alt=\"\" width=\"24\" height=\"24\" data-recalc-dims=\"1\" \/>Seconda osservazione:<\/strong> CLB_thread_list ::Start() manda in esecuzione tutti i thread figli\u00a0 chiamandone la funzione Start(), quindi lancia un thread interno di attesa terminazione.<\/p>\n<h4><\/h4>\n<p><!--nextpage-->Abbiamo visto come lanciare i thread gestiti da CLB_thread;\u00a0 abbiamo scritto che la funzione Start() ha, appunto, il compito di lanciare i thread, e che il suo contenuto \u00e8 specifico di ciascuna classe derivata; una scrittura minimale, che ha solo\u00a0 il compito di lanciare il thread, contiene semplicemente la macro\u00a0 __thread_exec(thread_name). E&#8217; questo il caso della\u00a0 THREAD_calc_dither::Start(), di seguito riportata:<\/p>\n<pre class=\"lang:default decode:true\">\t\/** lancia il thread in esecuzione\r\n\t*\/\r\n\tbool THREAD_calc_dither::Start()\r\n\t{\r\n\t\t__getstr\r\n\t\t__thread_exec(calc_dither)\r\n\t\treturn true;\r\n\t}\r\n\r\n<\/pre>\n<h4>__thread_exec<\/h4>\n<p>la macro, parte del gruppo di comandi di CLB_lang, ha il compito di mandare in esecuzione il thread denominato <span style=\"color: #008000;\"><em>calc_dither<\/em><\/span><\/p>\n<pre class=\"lang:default decode:true\">__thread_exec(calc_dither)<\/pre>\n<p>In questo caso la funzione Start() non ha altro compito, quindi la sua scrittura \u00e8 semplificata. Ci sono casi in cui la Start() svolge compiti pi\u00f9 complessi, ad esempio pu\u00f2 preparare\/analizzare\u00a0 i dati prima del comando <span style=\"color: #008000;\"><em>__thread_exec <\/em><\/span>, oppure potrebbe testare la correttezza dei parametri forniti o dover valutare le condizioni di esecuzione del thread, o altro.. in questo caso, qualor il thread non fosse eseguibile, rimanderebbe false.<\/p>\n<p>Analizzeremo ora le modalit\u00e0 di costruzione del thread interno alla classe derivata da CLB_thread.<\/p>\n<p>Lo faremo ancora una volta esponendo il codice della classe che stiamo usando come esempio:\u00a0 THREAD_calc_dither; come abbiamo avuto occasione di osservare, il calcolo della retinatura consiste nel mandare in esecuzione contemporanea pi\u00f9 threads, uno per ciascun canale graytone dell&#8217;immagine. <a href=\"#ciclo_di_thread_di_retinatura\">Per farlo abbiamo generato un gruppo di thread<\/a> figli della istanza CLB_thread_list\u00a0 \u00a0_$str-&gt;threads. Gli n thread eseguiti sono esattamente la stessa funzione interna al codice della classe THREAD_calc_dither, ma con parametri ovviamente diversi.<\/p>\n<p><!--nextpage-->Un thread interno a CLB_thread \u00e8 definito attraverso tre funzioni, definite\u00a0 usando le macro CLB_lang<\/p>\n<ol>\n<li>La prima funzione , che \u00e8 di inizializzazione, \u00e8 descritta fra le due macro <span style=\"color: #008000;\"><em>__function_thread_init &#8230;\u00a0 __function_end.<\/em><\/span><\/li>\n<li>La seconda funzione , che \u00e8 chiamata a conclusione del thread, \u00e8 descritta fra le due macro <span style=\"color: #008000;\"><em>__function_thread_close&#8230;\u00a0 __function_end.<\/em><\/span><\/li>\n<li>La terza funzione, il thread da eseguire, \u00e8 scritta nel blocco\u00a0 <em><span style=\"color: #008000;\">__thread_function(calc_dither)\u00a0 &#8230;\u00a0 __thread_end.<\/span><\/em><\/li>\n<\/ol>\n<p>I comandi macro nascondono tutta la complessit\u00e0 di controllo degli eventi connessa alla gestione del thread, quali le semaforizzazioni, la risposta egli eventi standard (sospensione, stop, continuazione) lanciati dall&#8217;esterno, o di attesa di eventi dall&#8217;interno (waiting di eventi esterni..). Sono uno strumento per standardizzare i controlli del processo gestito dal thread,<\/p>\n<p>Il codice, relativo alla classe THREAD_calc_dither usata come esempio \u00e8 sotto riportato.<\/p>\n<pre class=\"lang:default decode:true\" title=\"codice del thread\">\/** funzione che prepara i dati del thread \r\n*\/\r\n__function_thread_init\r\n\r\n__function_end\r\n\r\n\/** disalloca i dati non pi\u00f9 necessari allocati nel thread..\r\n*\/\r\n__function_thread_close\r\n\r\n__function_end\r\n\r\n__thread_function(calc_dither)\r\n\t\t\t\t\r\n\t__thr_pop_p(ichn,IMCHN)\t\t\t\/\/ canale da retinare\r\n\t__thr_pop_p(dth,DITHER)\t\t\t\/\/ modello di dithering usato\r\n\t__thr_pop_p(dx,int)\t\t\t\t\/\/ dimensioni mappa generata\r\n\t__thr_pop_p(dy,int)\r\n\t__thr_pop_p(_DENSITY,CURVE);\t\t\/\/ curva di correzione densit\u00e0\r\n\r\n\tint siz=1;\r\n\r\n\tif (!IBF.OpenTempFile(*dx,*dy,siz))\r\n\t\tEXIT_TASK\r\n\r\n\tDOC_AREA *sz=ichn-&gt;channel.GetSize();\r\n\r\n\t\/\/ scala da applicare\r\n\tdouble scy=(double)sz-&gt;dy\/(double)*dy;\r\n\tdouble scx=(double)sz-&gt;dx\/(double)*dx;\r\n\r\n\t__$btm_Open((&amp;(ichn-&gt;channel)))\r\n\r\n\tdth-&gt;StartFiltering();\r\n\r\n\tUBYTE *src=new UBYTE[*dx];\t\/\/ linea da scalare\r\n\t_$str-&gt;src = src;\r\n\r\n\tint npts = 0;\r\n\r\n\t\/\/ tabella densit\u00e0 calcolata\r\n\tif (_DENSITY)\r\n\t{\r\n\t\t_$str-&gt;_dens = _DENSITY-&gt;Get_points(&amp;npts);\r\n\t\tif (npts != 101)\r\n\t\t{\r\n\t\t\t__trace(L\"numero di punti curva densit\u00e0 sbagliato!\")\r\n\t\t}\r\n\t}\r\n\r\n\t{\r\n\r\n\t\tfor (int y = 0; y &lt; *dy; y++) \r\n               {\r\n    \t\t      if (!(y % 100)) \r\n                     {\r\n\t\t        __test_thread_status\r\n\t\t\t__thr_sig_perc(((float)y*100.0f) \/ (float)*dy)\r\n\t\t     }\r\n\t\t     UBYTE *buf = BPIX(_BMAN, 0, (int)(scy*y));\t\/\/ legge la linea sorgente UBYTE\r\n\r\n#define _DENS(v) _$str-&gt;_dens[v].Y\r\n\r\n                        \/\/ scalatura della linea originale;\r\n\t\t\tif (_DENSITY) {\r\n\t\t\t\tfor (int x = 0; x &lt; *dx; x++)\r\n\t\t\t\t\tsrc[x] = (UBYTE)(2.55f*(float)_DENS(buf[(int)(scx*x)]));\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\tfor (int x = 0; x &lt; *dx; x++)\r\n\t\t\t\t\tsrc[x] = (UBYTE)(2.55f*(float)buf[(int)(scx*x)]);\r\n\r\n\t\t\tUBYTE *map = IBF.GetLine(y, true);\r\n\t\t\tdth-&gt;Filter(map, src, *dx);\r\n\t\t}\r\n\t\tichn-&gt;channel.FlushToFile();\t\t\/\/ rilascia nuovamente il canale su file temporaneo\r\n\t\t__thr_sig_perc(100.0f);\r\n\t}\r\n__thread_end  \r\n\r\n\r\n<\/pre>\n<p>Nel caso in discussione le funzioni di inizializzazione (<span style=\"color: #008000;\"><em>__function_thread_init<\/em><\/span>) e terminazione (<span style=\"color: #008000;\"><em>__function_thread_close)\u00a0<\/em><\/span>, chiamate automaticamente dall&#8217;interno del thread attraverso i comandi CLB_lang,\u00a0 sono completamente vuote, non avendo compiti da svolgere\u00a0 ( ad esempio avrebbe potuto allocare o disallocare dati usati nel thread main..)<\/p>\n<h3><strong>__thread_function( <span style=\"color: #008000;\"><em>calc_dither<\/em> <\/span>)\u00a0 { &#8230;.. } __thread_end\u00a0<\/strong><\/h3>\n<p>Il blocco definisce il thread\u00a0 di nome <em><span style=\"color: #008000;\">calc_thread<\/span> <\/em>eseguito mediante il comando<em>\u00a0 <span style=\"color: #008000;\">__thread_exec(calc_dither)\u00a0 <\/span><\/em>dalla funzione Start(). Si possono osservare un insieme di macro CLB_lang che svolgono diverse funzioni:<\/p>\n<h3>__thr_pop_p(ptr,type)<\/h3>\n<p>estrae uno dei parametri passati atttraverso la <em><span style=\"color: #008000;\">__thr_push_p<\/span><\/em><span style=\"color: #808080;\"> in fase di allocazione del thread: <em><span style=\"color: #008000;\">ptr<\/span> <\/em>\u00e8 il nome di un puntatore di tipo <em><span style=\"color: #008000;\">type <\/span><\/em><\/span>inizializzato mediante questa macro.<\/p>\n<p>La macro \u00e8 richiamata pi\u00f9 volte per\u00a0 ricevere, nell&#8217;ordine di immissione, tutti i parametri passati alla classe mediante <em><span style=\"color: #008000;\">CLB_thread::Set_argument_list(..)<\/span><\/em> o la sequenza di comandi <em><span style=\"color: #008000;\">__thr_push_p.<\/span><\/em><\/p>\n<p>Il corpo della funzione contiene le istruzioni necessarie al compito assegnato, ma non sono argomento di questo articolo. Vengono invece discusse alcune macro di <em><span style=\"color: #008000;\">CLB_lang<\/span> <\/em>usate nel ciclo di esecuzione: <em><span style=\"color: #008000;\">__test_thread_status\u00a0<\/span> <\/em>e <em><span style=\"color: #008000;\">__thr_sig_perc<\/span><\/em>.<\/p>\n<h3><span style=\"color: #000000;\"><em>__test_thread_status\u00a0 <\/em><\/span><\/h3>\n<p>\u00e8 un comando macro estremamente importante, che ha il compito di analizzare lo stato del thread ed eventualmente compiere i passaggi associati. osserviamone la definizione:<\/p>\n<pre class=\"lang:default decode:true\">#define __test_thread_status { __test_thread_paused __test_thread_exit }\r\n<\/pre>\n<p>la macro esegue in sequenza due altre macro <em><span style=\"color: #008000;\">__test_thread_paused\u00a0<\/span> <\/em>e <em><span style=\"color: #008000;\">__test_thread_exit , <\/span><\/em><span style=\"color: #808080;\">\u00a0cos\u00ec definite:<\/span><\/p>\n<h3>__test_thread_paused<\/h3>\n<pre class=\"lang:default decode:true\">#define __test_thread_paused \t\tif (__event_verified(EV_PAUSE_THR)) { __event_set( EV_PAUSEED_THR) __event_wait(EV_CONTINUE_THR); }\r\n<\/pre>\n<p>La macro verifica che sia verificato l&#8217;evento <em><span style=\"color: #008000;\">EV_PAUSE_THR<\/span> <\/em>(attivato da qualcuno all&#8217;esterno o all&#8217;interno del thread\u00a0 chiamando la funzione<span style=\"color: #008000;\"><em> CLB_thread::Suspend()<\/em><\/span> ) e, se si, assegna un flag ed attende che sia verificato l&#8217;evento <span style=\"color: #008000;\">EV_CONTINUE_THR<\/span> (macro <em><span style=\"color: #008000;\">__event_wait<\/span><\/em>(..)). fino a quel\u00a0 momento il thread rimane in uno stato di attesa.\u00a0 \u00a0L&#8217;evento <span style=\"color: #008000;\"><em>EV_CONTINUE_THR\u00a0<\/em> <\/span>\u00e8 alzato dall&#8217;esterno attraverso\u00a0 la <span style=\"color: #008000;\"><em> CLB_thread::Continue()<\/em> <\/span>.<\/p>\n<h3>__thr_sig_perc(perc)<\/h3>\n<p>La macro segnala al gestore dei thread quale \u00e8 la percentuale del ciclo attualmente eseguita. La segnalazione \u00e8 usata da un thread (CLB_thread_list) per visualizzare lo stato del thread specifico, o dell&#8217;insieme dei thread figli.\u00a0 Se non \u00e8 attivo un thread di cattura della percentuale, non succede niente.<\/p>\n<p><strong><span style=\"color: #ff0000;\"><img decoding=\"async\" data-attachment-id=\"3285\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3285\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-orig-size=\"24,24\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"alignleft size-full wp-image-3285\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?resize=24%2C24&#038;ssl=1\" alt=\"\" width=\"24\" height=\"24\" data-recalc-dims=\"1\" \/><\/span><\/strong><span style=\"color: #008000;\"> notare che\u00a0 le macro\u00a0 <em>__test_thread_status\u00a0<\/em> e\u00a0 <em>__thr_sig_perc\u00a0<\/em> sono state inserite\u00a0 in\u00a0 un blocco che viene eseguito ogni cento linee analizzate: la scelta fatta dal programmatore \u00e8 stata di non eseguire il test con frequenza eccessiva, considerando sufficiente quella scelta..<\/span><\/p>\n<pre class=\"lang:default decode:true \">.....\r\n\t\tfor (int y = 0; y &lt; *dy; y++) \r\n               {\r\n    \t\t      if (!(y % 100)) \r\n                     {\r\n\t\t        __test_thread_status\r\n\t\t\t__thr_sig_perc(((float)y*100.0f) \/ (float)*dy)\r\n\t\t     }\r\n.....\r\n.....\r\n.....<\/pre>\n<p><strong><span style=\"color: #ff0000;\"><img decoding=\"async\" data-attachment-id=\"3285\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/?attachment_id=3285\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-orig-size=\"24,24\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"word-image\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?fit=24%2C24&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"alignleft size-full wp-image-3285\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2018\/03\/word-image-97.png?resize=24%2C24&#038;ssl=1\" alt=\"\" width=\"24\" height=\"24\" data-recalc-dims=\"1\" \/><\/span><\/strong><\/p>\n<p><span style=\"color: #008000;\"><em>E&#8217; importante osservare che non \u00e8 obbligatorio inserire queste macro nel codice; Se non presenti, il thread don potr\u00e0 essere interrotto dall&#8217;esterno (__test_thread_paused) o non fornir\u00e0 informazioni sul suo stato di esecuzione (__thr_sig_perc)<\/em><\/span><\/p>\n<p>&nbsp;<\/p>\n<!--nextpage-->\n<p>Il codice di esempio fino a qui descritto, apparentemente non svolge alcuna\u00a0 azione dopo il lancio del gruppo di thread; e\u00a0 potrebbe essere una delle possibilit\u00e0: un programma lancia uno o pi\u00f9 thread che si concludono (o rimangono in standby\u00a0 fino a nuovi ordini) disinteressandosi del ricultato.<\/p>\n<p>E&#8217; il caso ad esempio dei thread di stampa (TSK_SCREEN_RENDER)\u00a0 eseguiti attraverso le classe RENDERING_ENGINE: questi thread possono essere sospesi o cancellati, ma non \u00e8 necessario attendere la fine della loro esecuzione.<\/p>\n<p>Nell&#8217;esempio fin qui mostrato invece la logica del programma richiedeva che fosse attesa la terminazione dei thread, per eseguire altre operazioni; ricordiamo che\u00a0 abbiamo usato la classe CLB_thread_list, che ha lanciato un insieme di thread figli (uno per canale graytone)\u00a0 assegnati attraverso la funzione CLB_thread_list::Start() posta alla fine della funzione CREATE_DITHERING . Di seguito evidenziamo, nella funzione, solo l&#8217;istruzione finale, Start() dell&#8217; istanza CLB_thread_list usata.<\/p>\n<pre class=\"lang:default decode:true\">\tbool CREATE_DITHERING(CLASS_STR)\r\n\t{\r\n             ..... \r\n             ......\r\n\t    _$str-&gt;threads-&gt;UseDisplayProgressWindow(__translate(\"Create Screens channels\"), __translate(\" Wait: the program is building dithered channels..\"));\r\n\t     return _$str-&gt;threads-&gt;Start();\r\n\t}\r\n<\/pre>\n<p>La funzione CLB_thread_list ::Start(..) lancia al suo interno i threads figli assegnati, quindi lancia un thread interno che semplicemente rimane in attesa della terminazione degli stessi. In questa attesa intercetta lo stato di esecuzione percentuale dei tread assegnati, e lo visualizza nella finestra modale definita dall&#8217;istruzione _$str-&gt;threads-&gt;UseDisplayProgressWindow(..) nella funzione\u00a0CREATE_DITHERING.<\/p>\n<p>Lo stato di esecuzione \u00e8 automaticamente visualizzato in questa finestra modale:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"3847\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/framework\/creazione-di-classi-thread-in-colibri\/admin\/2019\/11\/attachment\/thr_dithering\/\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?fit=399%2C199&amp;ssl=1\" data-orig-size=\"399,199\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"thr_dithering\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?fit=300%2C150&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?fit=399%2C199&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\"size-full wp-image-3847 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?resize=399%2C199&#038;ssl=1\" alt=\"\" width=\"399\" height=\"199\" srcset=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?w=399&amp;ssl=1 399w, https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/thr_dithering.jpg?resize=300%2C150&amp;ssl=1 300w\" sizes=\"(max-width: 399px) 100vw, 399px\" data-recalc-dims=\"1\" \/>La finestra \u00e8 aggiornata fino a chiusura regolare di tutti i thread o loro interruzione con il tasto <strong>Exit<\/strong>.<\/p>\n<p>Notare i messaggi in alto nella finestra: sono quelli definiti con la\u00a0 funzione<\/p>\n<p style=\"text-align: center;\">_$str-&gt;threads-&gt;UseDisplayProgressWindow(&#8230;)<\/p>\n<p>La finestra indica il numero di thread ancora attivi, tempo passato e rimanente e % complessiva del lavoro svolto.<\/p>\n<p><span style=\"color: #808080;\">La CLB_thread_list ::Start(..)\u00a0 infine chiude l a finestra e\u00a0 rimanda true se i thread sono tutti terminati correttamente: in questo caso il passaggio successivo sar\u00e0 di mostrare il risultato..<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<hr \/>\n<h3><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"3848\" data-permalink=\"https:\/\/www.colorwave.it\/blog\/framework\/creazione-di-classi-thread-in-colibri\/admin\/2019\/11\/attachment\/conclusione\/\" data-orig-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/conclusione.jpg?fit=150%2C91&amp;ssl=1\" data-orig-size=\"150,91\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"conclusione\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/conclusione.jpg?fit=150%2C91&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/conclusione.jpg?fit=150%2C91&amp;ssl=1\" tabindex=\"0\" role=\"button\" class=\" wp-image-3848 alignleft\" src=\"https:\/\/i0.wp.com\/www.colorwave.it\/blog\/wp-content\/uploads\/2019\/11\/conclusione.jpg?resize=248%2C151&#038;ssl=1\" alt=\"\" width=\"248\" height=\"151\" data-recalc-dims=\"1\" \/><\/h3>\n<p><span style=\"color: #0000ff;\"><strong>In conclusione:<\/strong><\/span><\/p>\n<p><span style=\"color: #0000ff;\"><strong>\u00a0<\/strong><\/span>Abbiamo, in questo lungo articolo, discusso le funzionalit\u00e0 di un insieme di classi usate per la gestione dei thread nel framework di Colibr\u00ec. Non abbiamo esaurito l&#8217;argomento, poich\u00e9 esistono altre classi che sono utilizzate per eseguire i thread, e non abbiamo spiegato tutte le\u00a0 macro di CLB_lang a disposizione per gestire il flusso dei thread; in un prossimo articolo discuteremo anche altre classi utilizzabili per queste funzioni; in particolare affronteremo l&#8217;argomento relativo all&#8217;uso delle\u00a0 CLB_thread\u00a0 in programmazione concorrente, dove i thread scambiano dati e\u00a0 comunicano fra di loro utilizzando oltre che gli eventi i mutex.<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Colibri contiene diverse classi e definizioni\u00a0 per la gestione dei thread;\u00a0 tutte le classi e strutture di gestione dei threads sono contenute nel namespace CLB::Threads, definito nella dll CLB_000. In questo articolo vengono descritte le classi Thread_status\u00a0 e CLB_thread. La Thread_status fornisce&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"aside","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false,"jetpack_publicize_message":"Creazione di classi thread in Colibr\u00ec","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[90,19,120],"tags":[],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9rwsf-Z1","jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/3783"}],"collection":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/comments?post=3783"}],"version-history":[{"count":38,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/3783\/revisions"}],"predecessor-version":[{"id":3856,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/posts\/3783\/revisions\/3856"}],"wp:attachment":[{"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/media?parent=3783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/categories?post=3783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.colorwave.it\/blog\/wp-json\/wp\/v2\/tags?post=3783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}