• <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類[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類繼承并實(shí)現(xiàn)run方法:

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

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

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

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

            7?//?開啟線程?
            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類,并為Runnable類添加純虛函數(shù)run,需要特別注意的是Runnable類的虛析構(gòu)函數(shù),任何想要成為基類的class都應(yīng)該聲明析構(gòu)函數(shù)為virtual。
            Thread類直接繼承自Runnable,CLASS_UNCOPYABLE(Thread) 這一行用宏聲明Thread類不可拷貝,具體細(xì)節(jié)請(qǐng)看 考慮用Macro替換Uncopyable 。start成員函數(shù)和Java中的一樣,用來(lái)開啟一個(gè)線程,join成員函數(shù)用來(lái)阻塞當(dāng)前線程直到開啟的線程執(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類繼承
            ?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ù),如果你覺得從Thread類繼承或者實(shí)現(xiàn)Runnable接口還不夠簡(jiǎn)潔,下一篇會(huì)有一個(gè)比較好的改進(jìn)。

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

            Feedback

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

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

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

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

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

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

            # re: 從Win32 API封裝Thread類[1] 2008-10-10 01:23 OwnWaterloo

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

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

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

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

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

            # re: 從Win32 API封裝Thread類[1] 2008-10-10 01:36 OwnWaterloo

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

            1.單下劃線開始的標(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 線程并不停止
            如果主線程沒有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類[1] 2008-10-10 09:15 螞蟻終結(jié)者

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

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

            @OwnWaterloo
            建議:
            1.單下劃線開始的標(biāo)識(shí)符?
            這個(gè)是編程風(fēng)格問(wèn)題,很難說(shuō)出哪個(gè)更好哪個(gè)更差,正所謂蘿卜白菜各有所愛,個(gè)人認(rèn)為成員變量無(wú)論是下劃線開始(如:_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類[1][未登錄] 2013-06-08 17:19 Jackie

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

            欧美激情精品久久久久| 国产精品伊人久久伊人电影| 久久久久久人妻无码| 久久精品一区二区三区不卡| 日本一区精品久久久久影院| 人妻无码精品久久亚瑟影视| 久久久久久久亚洲Av无码| 久久久久亚洲?V成人无码| 大香伊人久久精品一区二区| 伊人久久综在合线亚洲2019| 国内精品综合久久久40p| 久久91亚洲人成电影网站| 久久受www免费人成_看片中文| 精品少妇人妻av无码久久| 色偷偷91久久综合噜噜噜噜| 亚洲一区二区三区日本久久九| 亚洲精品蜜桃久久久久久| 一本色道久久88综合日韩精品 | 人妻少妇精品久久| 国产91色综合久久免费分享| 久久精品免费一区二区| 精品99久久aaa一级毛片| 香蕉久久夜色精品国产小说| 2021精品国产综合久久| 日本强好片久久久久久AAA| 久久天天躁狠狠躁夜夜2020一| 久久精品国产色蜜蜜麻豆| 国产精品伦理久久久久久| 久久se精品一区精品二区| 久久精品国产亚洲av日韩| 亚洲女久久久噜噜噜熟女| 一本一道久久综合狠狠老| 久久狠狠爱亚洲综合影院| 伊人久久大香线焦AV综合影院| 精品久久亚洲中文无码| 久久狠狠爱亚洲综合影院| 国产成年无码久久久免费| 久久精品亚洲AV久久久无码| 亚洲午夜久久久久久噜噜噜| 人妻久久久一区二区三区| 国产情侣久久久久aⅴ免费|