• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            #ant

            The dreams in which I'm dying are the best I've ever had...

            從Win32 API封裝Thread類(lèi)[1]

            前幾天在學(xué)Windows多線程程序設(shè)計(jì),發(fā)現(xiàn)Win32 API用起來(lái)確實(shí)不怎么方便,特別是對(duì)于C++程序員。于是實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的封裝,技術(shù)含量當(dāng)然不高,不過(guò)用起來(lái)還是比較方便的。如果你熟悉Java,你會(huì)發(fā)現(xiàn)這個(gè)實(shí)現(xiàn)有點(diǎn)像Java的Thread,在Java中有兩種方法可以創(chuàng)建一個(gè)Thread:

            1.從Thread類(lèi)繼承并實(shí)現(xiàn)run方法:

            1?class?MyThread?extends ?Thread?{
            2?????public?void
            ?run()?{
            3?
            ????????...
            4?
            ????}?
            5?
            };
            6?

            7?//開(kāi)啟線程
            8?MyThread?thread?=?new ?MyThread;
            9?thread.start();

            2.聲明一個(gè)類(lèi)實(shí)現(xiàn)Runnable接口并實(shí)現(xiàn)run方法:

            1?class?MyRunnable?implements ?Runnable?{
            2?????public?void
            ?run()?{
            3?
            ????????...
            4?
            ????}
            5?
            };
            6?

            7?//?開(kāi)啟線程?
            8?MyThread?thread?=?new?MyThread(new ?MyRunnable);
            9?thread.start();


            具體實(shí)現(xiàn)
            Java的實(shí)現(xiàn)方式還算優(yōu)雅,我們也可以在C++中模擬,由于篇幅所限,在這里我們只關(guān)注基本功能的實(shí)現(xiàn):
            thread.h
            ?1?#ifndef?THREAD_H
            ?2?
            #define?THREAD_H
            ?3?

            ?4?#include?<windows.h>
            ?5?
            ?6?#define?CLASS_UNCOPYABLE(classname)?\
            ?7?????private
            :?\
            ?8?????classname(const?classname&
            );?\
            ?9?????classname&?operator=(const?classname&
            );
            10?

            11?struct?Runnable?{
            12?????virtual?void?run()?=?0
            ;
            13?????virtual?~
            Runnable()?{}
            14?
            };
            15?

            16?class?Thread?:?public?Runnable?{
            17?
            ????CLASS_UNCOPYABLE(Thread)
            18?public
            :
            19?????explicit?Thread(Runnable* target?=?0
            );
            20?????virtual?~
            Thread();
            21?????virtual?void
            ?run()?{}
            22?????void
            ?start();
            23?????void
            ?join();
            24?private
            :
            25?????static?unsigned?__stdcall?threadProc(void*
            param);
            26?private
            :
            27?????Runnable*
            _target;
            28?
            ????HANDLE?_handle;
            29?
            };
            30?

            31?#endif/*THREAD_H*/

            在上面的代碼中我們先定義一個(gè)Runnable類(lèi),并為Runnable類(lèi)添加純虛函數(shù)run,需要特別注意的是Runnable類(lèi)的虛析構(gòu)函數(shù),任何想要成為基類(lèi)的class都應(yīng)該聲明析構(gòu)函數(shù)為virtual。
            Thread類(lèi)直接繼承自Runnable,CLASS_UNCOPYABLE(Thread) 這一行用宏聲明Thread類(lèi)不可拷貝,具體細(xì)節(jié)請(qǐng)看 考慮用Macro替換Uncopyable 。start成員函數(shù)和Java中的一樣,用來(lái)開(kāi)啟一個(gè)線程,join成員函數(shù)用來(lái)阻塞當(dāng)前線程直到開(kāi)啟的線程執(zhí)行完畢。threadProc作為靜態(tài)成員函數(shù)用來(lái)傳遞給_beginthreadex,至于為什么用_beginthreadex代替CreateThread請(qǐng)問(wèn)Google。初步的實(shí)現(xiàn)都比較簡(jiǎn)單,直接貼上代碼:
            thread.cpp
            ?1?#include?"thread.h"
            ?2?#include?<process.h>?// for?_beginthreadex
            ?3?
            ?4?Thread::Thread(Runnable* target?/*=?0*/)
            ?5?:_target(target
            )
            ?6?,_handle(0
            )?{
            ?7?

            ?8?}
            ?9?

            10?Thread::~Thread()?{
            11?????if?(_handle?!=?0
            )
            12?
            ????????CloseHandle(_handle);
            13?????if?(_target?!=?0
            )
            14?
            ????????delete?_target;
            15?
            }
            16?

            17?void?Thread::start()?{
            18?????if?(_handle?!=?0
            )
            19?????????return
            ;
            20?
            ????unsigned?id;
            21?????_handle?=?reinterpret_cast<HANDLE>
            (
            22?????????_beginthreadex(0,?0,?threadProc,?this,?0,?&
            id)
            23?
            ????????);
            24?
            }
            25?

            26?void?Thread::join()?{
            27?????if(_handle?!=?0
            )?{
            28?
            ????????WaitForSingleObject(_handle,?INFINITE);
            29?
            ????????CloseHandle(_handle);
            30?????????_handle?=?0
            ;
            31?
            ????}
            32?
            }
            33?

            34?unsigned?__stdcall?Thread::threadProc(void* param)?{
            35?????Thread* p?=?static_cast<Thread*>
            (param);
            36?????if?(p->_target?!=?0
            )
            37?????????p->_target->
            run();
            38?????else

            39?????????p->run();
            40?????return?0
            ;
            41?}

            下面是測(cè)試代碼:
            test.cpp
            ?1?#include?"thread.h"
            ?2?#include?<iostream>
            ?3?
            ?4?using?namespace?std;
            ?5?

            ?6?//第一種方法,從Thread類(lèi)繼承
            ?7?struct?MyThread?:?public?Thread?{
            ?8?????virtual?void
            ?run()?{
            ?9?????????for?(int?i?=?0;?i?<?5;?++
            i)?{
            10?????????????cout?<<?"MyThread?Running..."?<<?i?<<
            ?endl;
            11?????????????Sleep(100
            );
            12?
            ????????}
            13?
            ????}
            14?
            };
            15?

            16?//第二種方法,“實(shí)現(xiàn)”Runnable接口
            17?struct?MyRunnable?:?public?Runnable?{
            18?????virtual?void
            ?run()?{
            19?????????for?(int?i?=?0;?i?<?5;?++
            i)?{
            20?????????????cout?<<?"MyRunnable?Running..."?<<?i?<<
            ?endl;
            21?????????????Sleep(300
            );
            22?
            ????????}
            23?
            ????}
            24?
            };
            25?

            26?int?main()?{
            27?

            28?????MyThread?thread1;
            29?????Thread?thread2(new
            ?MyRunnable());
            30?
            ????thread1.start();
            31?
            ????thread2.start();
            32?
            ????thread1.join();
            33?
            ????thread2.join();
            34?

            35?????return?0;
            36?}

            可能的運(yùn)行結(jié)果:
            MyThread Running...0
            MyRunnable Running...0
            MyThread Running...1
            MyThread Running...2
            MyRunnable Running...1
            MyThread Running...3
            MyThread Running...4
            MyRunnable Running...2
            MyRunnable Running...3
            MyRunnable Running...4


            如果你熟悉boost庫(kù),你會(huì)知道boost庫(kù)的Thread構(gòu)造函數(shù)可以接受普通函數(shù)和函數(shù)對(duì)象作為參數(shù),如果你覺(jué)得從Thread類(lèi)繼承或者實(shí)現(xiàn)Runnable接口還不夠簡(jiǎn)潔,下一篇會(huì)有一個(gè)比較好的改進(jìn)。

            posted on 2007-08-30 10:18 螞蟻終結(jié)者 閱讀(4615) 評(píng)論(8)  編輯 收藏 引用 所屬分類(lèi): C++

            Feedback

            # re: 從Win32 API封裝Thread類(lèi)[1] 2007-08-31 15:18 重劍

            受益匪淺啊   回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-02-26 17:51 sd

            太簡(jiǎn)單了  回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-07-25 22:46 Robinfoxnan

            看了樓主的TEA,和strlen覺(jué)得分析的很好,
            但是,關(guān)于多線程,
            在侯捷的《windows多線程程序設(shè)計(jì)》中說(shuō),建議不使用_beginthreadex之類(lèi)純API函數(shù),原因是在使用了線程本地存儲(chǔ)的函數(shù),比如GetLastError()之類(lèi)的函數(shù)后,運(yùn)行庫(kù)比如VC++,會(huì)幫你建立一些我們看不到的結(jié)構(gòu)體,會(huì)容易導(dǎo)致內(nèi)存泄露,建議使用AfxBeginThread()類(lèi),特定開(kāi)發(fā)環(huán)境提供的函數(shù)或者類(lèi),比如CWinThread。
            可以參考該書(shū)第8章!  回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-10-10 01:23 OwnWaterloo

            @Robinfoxnan
            我?guī)蜆侵骰啬懔?~~

            侯捷的書(shū), 肯定說(shuō)的是不要使用 CreateTread 這個(gè)API
            如果他說(shuō)的是不要使用 _beginthreadex , 那他該被拖出去打。

            至于AfxBeginThread ,windows平臺(tái)下寫(xiě)程序一定要和MFC扯上關(guān)系么?

            既然你提到了AfxBeginThread, 你可以去看一下MFC的源碼, MFC80, 它就是使用的 _beginthreadex ~~

              回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-10-10 01:36 OwnWaterloo

            我有2個(gè)建議, 一個(gè)可以慎重考慮一下, 另外一個(gè)可以完全不理睬。
            還有2個(gè)疑問(wèn) ……

            1.單下劃線開(kāi)始的標(biāo)識(shí)符?

            2.將windows.h 從thread.h中移走
            .h
            class Thread {
            //
            private:
            uintptr_t handle_;
            }

            .cpp
            handle_ = _beginthreadex 這個(gè)可以直接賦值
            CloseHandle( reinterpret_cast<HANDLE>( handle_ ); 這個(gè)要自己轉(zhuǎn)
            雖然麻煩一點(diǎn), 但是將 windows.h 隔離到了頭文件之外




            疑問(wèn):
            1. Thread的析構(gòu)

            10 Thread::~Thread() {
            11 if (_handle != 0)
            12 CloseHandle(_handle);
            13 if (_target != 0)
            14 delete _target;
            15 }

            CloseHandle 線程并不停止
            如果主線程沒(méi)有join delete _target; 后 線程還在run

            這是線程函數(shù)
            34 unsigned __stdcall Thread::threadProc(void *param) {
            35 Thread *p = static_cast<Thread*>(param);
            36 if (p->_target != 0)
            37 p->_target->run();
            38 else
            39 p->run();
            40 return 0;
            41 }

            37 行, 如果被delete, 而且run訪問(wèn)了數(shù)據(jù), 而不僅僅是打印一些console消息, 肯定會(huì)引發(fā)錯(cuò)誤。


            疑問(wèn)是: join 是慣例? 規(guī)范? 還是僅僅是boost的示例而已。


            2.Thread 似乎并不需要從 Runable 繼承。
            完全可以設(shè)計(jì)成 Thread是Runable的容器。

            疑問(wèn)是: 僅僅是為了模仿Java的行為?
              回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-10-10 09:15 螞蟻終結(jié)者

            @Robinfoxnan
            OwnWaterloo回答的也是我想回答的,我就不多說(shuō)了。  回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1] 2008-10-10 09:35 螞蟻終結(jié)者

            @OwnWaterloo
            建議:
            1.單下劃線開(kāi)始的標(biāo)識(shí)符?
            這個(gè)是編程風(fēng)格問(wèn)題,很難說(shuō)出哪個(gè)更好哪個(gè)更差,正所謂蘿卜白菜各有所愛(ài),個(gè)人認(rèn)為成員變量無(wú)論是下劃線開(kāi)始(如:_handle)還是下劃線結(jié)尾(如:handle_),又或者是用匈牙利命名法,只要在編碼中始終保持一種風(fēng)格就好。編碼風(fēng)格對(duì)程序員來(lái)說(shuō)可能是一種信仰。

            2.將windows.h 從thread.h中移走
            這個(gè)確實(shí)是可以考慮,如果考慮到跨平臺(tái)的話。

            疑問(wèn):
            1. Thread的析構(gòu)
            據(jù)我所知,join應(yīng)該是等待線程結(jié)束的慣用法,Java.Thread,boost.Thread都通過(guò)join來(lái)保證線程的安全結(jié)束。是否是規(guī)范我也不清楚,貌似join是POSIX中線程取消規(guī)范中的一個(gè)?

            2.Thread 似乎并不需要從 Runable 繼承
            是不需要繼承Runnable的,這樣只是模仿Java的行為。
              回復(fù)  更多評(píng)論   

            # re: 從Win32 API封裝Thread類(lèi)[1][未登錄](méi) 2013-06-08 17:19 Jackie

            這里有個(gè)問(wèn)題, 是 如果你沒(méi)有join的話, 線程對(duì)象就會(huì)被馬上析構(gòu), 程序出現(xiàn)崩潰.
            所以我把線程對(duì)象創(chuàng)建在堆上面了, 然后在Run調(diào)用完之后在threadProc里面delete 完成  回復(fù)  更多評(píng)論   

            香蕉久久夜色精品国产小说| 久久国产高潮流白浆免费观看| 99久久国产亚洲高清观看2024| 精品一久久香蕉国产线看播放| 久久久久国产一区二区| 亚洲精品NV久久久久久久久久| 亚洲国产精品无码成人片久久| 久久99精品国产自在现线小黄鸭 | 久久国产免费观看精品| 狠狠干狠狠久久| 久久天天躁狠狠躁夜夜不卡| 久久久久久国产精品无码超碰| 欧美精品久久久久久久自慰| 国产精品视频久久久| 亚洲欧美另类日本久久国产真实乱对白 | 精品无码久久久久久午夜| 久久久人妻精品无码一区| 国产成人久久精品激情| 一级做a爰片久久毛片看看| 亚洲狠狠综合久久| 久久久噜噜噜久久中文福利| 久久乐国产综合亚洲精品| 精品国产青草久久久久福利| 欧美午夜精品久久久久免费视| 日日狠狠久久偷偷色综合0 | 久久精品午夜一区二区福利| 亚洲国产精品无码久久青草| 亚洲综合婷婷久久| 青青草国产精品久久久久| 久久精品99久久香蕉国产色戒| 精品多毛少妇人妻AV免费久久| 欧美日韩成人精品久久久免费看| 91久久精品视频| 91亚洲国产成人久久精品| 国产精品久久久久9999| 91精品国产综合久久精品| 国内精品久久久久| 精品一区二区久久久久久久网站| 国产麻豆精品久久一二三| 国产精品久久久久久吹潮| 日韩一区二区久久久久久|