• <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]

            前幾天在學Windows多線程程序設計,發現Win32 API用起來確實不怎么方便,特別是對于C++程序員。于是實現了一個簡單的封裝,技術含量當然不高,不過用起來還是比較方便的。如果你熟悉Java,你會發現這個實現有點像Java的Thread,在Java中有兩種方法可以創建一個Thread:

            1.從Thread類繼承并實現run方法:

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

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

            2.聲明一個類實現Runnable接口并實現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();


            具體實現
            Java的實現方式還算優雅,我們也可以在C++中模擬,由于篇幅所限,在這里我們只關注基本功能的實現:
            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*/

            在上面的代碼中我們先定義一個Runnable類,并為Runnable類添加純虛函數run,需要特別注意的是Runnable類的虛析構函數,任何想要成為基類的class都應該聲明析構函數為virtual。
            Thread類直接繼承自Runnable,CLASS_UNCOPYABLE(Thread) 這一行用宏聲明Thread類不可拷貝,具體細節請看 考慮用Macro替換Uncopyable 。start成員函數和Java中的一樣,用來開啟一個線程,join成員函數用來阻塞當前線程直到開啟的線程執行完畢。threadProc作為靜態成員函數用來傳遞給_beginthreadex,至于為什么用_beginthreadex代替CreateThread請問Google。初步的實現都比較簡單,直接貼上代碼:
            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?}

            下面是測試代碼:
            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?//第二種方法,“實現”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?}

            可能的運行結果:
            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庫,你會知道boost庫的Thread構造函數可以接受普通函數和函數對象作為參數,如果你覺得從Thread類繼承或者實現Runnable接口還不夠簡潔,下一篇會有一個比較好的改進。

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

            Feedback

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

            受益匪淺啊   回復  更多評論   

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

            太簡單了  回復  更多評論   

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

            看了樓主的TEA,和strlen覺得分析的很好,
            但是,關于多線程,
            在侯捷的《windows多線程程序設計》中說,建議不使用_beginthreadex之類純API函數,原因是在使用了線程本地存儲的函數,比如GetLastError()之類的函數后,運行庫比如VC++,會幫你建立一些我們看不到的結構體,會容易導致內存泄露,建議使用AfxBeginThread()類,特定開發環境提供的函數或者類,比如CWinThread。
            可以參考該書第8章!  回復  更多評論   

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

            @Robinfoxnan
            我幫樓主回你了 ~~

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

            至于AfxBeginThread ,windows平臺下寫程序一定要和MFC扯上關系么?

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

              回復  更多評論   

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

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

            1.單下劃線開始的標識符?

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

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




            疑問:
            1. Thread的析構

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

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

            這是線程函數
            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訪問了數據, 而不僅僅是打印一些console消息, 肯定會引發錯誤。


            疑問是: join 是慣例? 規范? 還是僅僅是boost的示例而已。


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

            疑問是: 僅僅是為了模仿Java的行為?
              回復  更多評論   

            # re: 從Win32 API封裝Thread類[1] 2008-10-10 09:15 螞蟻終結者

            @Robinfoxnan
            OwnWaterloo回答的也是我想回答的,我就不多說了。  回復  更多評論   

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

            @OwnWaterloo
            建議:
            1.單下劃線開始的標識符?
            這個是編程風格問題,很難說出哪個更好哪個更差,正所謂蘿卜白菜各有所愛,個人認為成員變量無論是下劃線開始(如:_handle)還是下劃線結尾(如:handle_),又或者是用匈牙利命名法,只要在編碼中始終保持一種風格就好。編碼風格對程序員來說可能是一種信仰。

            2.將windows.h 從thread.h中移走
            這個確實是可以考慮,如果考慮到跨平臺的話。

            疑問:
            1. Thread的析構
            據我所知,join應該是等待線程結束的慣用法,Java.Thread,boost.Thread都通過join來保證線程的安全結束。是否是規范我也不清楚,貌似join是POSIX中線程取消規范中的一個?

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

            # re: 從Win32 API封裝Thread類[1][未登錄] 2013-06-08 17:19 Jackie

            這里有個問題, 是 如果你沒有join的話, 線程對象就會被馬上析構, 程序出現崩潰.
            所以我把線程對象創建在堆上面了, 然后在Run調用完之后在threadProc里面delete 完成  回復  更多評論   

            中文字幕久久亚洲一区| 国产精品一久久香蕉国产线看 | 99久久er这里只有精品18| 久久精品www人人爽人人| 国产精品久久精品| 久久久久亚洲AV综合波多野结衣| 中文字幕亚洲综合久久菠萝蜜| 中文字幕精品久久久久人妻| 久久99精品久久久久久hb无码| 久久―日本道色综合久久| 亚洲精品国精品久久99热一| 久久国产热这里只有精品| 色综合久久久久无码专区 | 色婷婷噜噜久久国产精品12p| 97r久久精品国产99国产精| 久久人人爽人人澡人人高潮AV| 四虎国产精品成人免费久久| 三级韩国一区久久二区综合| 99久久精品午夜一区二区| 亚洲婷婷国产精品电影人久久| 久久精品人人做人人爽电影蜜月| 蜜臀久久99精品久久久久久| 99热成人精品热久久669| 久久99精品国产麻豆不卡| 国产综合久久久久久鬼色| 久久久午夜精品| 97久久国产露脸精品国产| 国产A级毛片久久久精品毛片| 国产精品久久久99| 香蕉久久久久久狠狠色| 伊人久久综合热线大杳蕉下载| 91精品国产综合久久香蕉| 97久久国产亚洲精品超碰热| 精产国品久久一二三产区区别| 久久99精品久久只有精品| 精品一二三区久久aaa片| 亚洲欧美日韩精品久久亚洲区| 久久男人AV资源网站| 99久久免费只有精品国产| 99久久www免费人成精品 | 国产精品天天影视久久综合网|