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

            我們的工程馬上就要發布,但是在一個干凈的,即沒有安裝vs2005的xp上運行(利用虛擬機測試)卻彈出下面得錯誤
            “由于應用程序配置不正確,應用程序未能啟動。重新安裝應用程序可能會糾正這個問題“
            在英文os上:
            This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.
            考慮到程序的運行環境問題,可能是由于沒有安裝.netFrameWork.但是后來安裝上之后仍然如故。郁悶。。。
            在網上找出了這些方法:
            方法一:
            在類似C:\Program Files\Microsoft Visual Studio 8\VC\redi
            st\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT 下找到了下列文件:
            msvcm80d.dll
            msvcp80d.dll
            msvcr80d.dll
            Microsoft.VC80.DebugCRT.manifest
            把這幾個文件拷貝到目標機器上,與運行程序同一文件夾或放到system32下,就可以正確運行了。
            其他release版、MFC程序什么的都是拷redist下相應文件夾下的文件就可以了,文件夾后都有標識!
            方法二:
            修改編譯選項,將/MD或/MDd 改為 /MT或/MTd,這樣就實現了對VC運行時庫的靜態鏈接,在運行時就不再需要VC的dll了。
            注:MSDN中對于在不同的配置下Link的LIB作了說明:
            C Runtime Library:
            開關 對應的庫 版本
            /MD MSVCRT.LIB 多線程DLL的Release版本
            /MDd MSVCRTD.LIB 多線程DLL的Debug版本
            /MT LIBCMT.LIB 多線程靜態鏈接的Release版本
            /MTd LIBCMTD.LIB 多線程靜態鏈接的Debug版本
            /clr MSVCMRT.LIB 托管代碼和非托管代碼混合
            /clr:pure MSVCURT.LIB 純托管代碼 
            C++ Standard Library:
            開關 對應的庫 版本
            /MD MSVCPRT.LIB 多線程DLL的Release版本
            /MDd MSVCPRTD.LIB 多線程DLL的Debug版本
            /MT LIBCPMT.LIB 多線程靜態鏈接的Release版本
            /MTd LIBCPMTD.LIB 多線程靜態鏈接的Debug版本 
            編譯器會自動根據編譯選項,選擇對應的LIB文件。一般情況下這不會出現問題。
            然而,在部分情況下,一旦你的程序的各個部分(LIB, OBJ…)并非由相同的編譯選項編譯出,而Link在一起的話,會出現各種各樣的看似很難解決的問題,這類問題主要以重復定義的錯誤形式存在,通常的解決方法也很簡單,就是選擇同樣的編譯選項進行編譯之后再Link
            方法三:
            工程-》屬性-》配置屬性-》常規-》MFC的使用,選擇“在靜態庫中使用mfc”
            這樣生成的exe文件應該就可以在其他機器上跑了。
            方法四:
            安裝vcredist_x86.exe

            這樣四步下來,大部分程序都應該可以運行了,但悲哀的是在我的測試機上還是報應用程序配置錯誤。無奈。。
            后打開vs2005的命令行,運行depends.exe,試圖找出程序啟動所依賴的dll,結果大失所望,虛擬機上這些dll都有。如此這般令人抓狂。
            最后把vs2005安裝目錄下的所有.manifest文件(可以搜索 *.manifest得到)都考到程序目錄下,程序奇跡般的可以運行。
            然后實驗,刪掉冗余的.manifest文件,只需要5個就夠了。它們是Microsoft.VC80.ATL.manifest
            Microsoft.VC80.CRT.manifest
            Microsoft.VC80.DebugCRT.manifest
            Microsoft.VC80.DebugMFC.manifest
            Microsoft.VC80.MFC.manifest

            posted @ 2009-11-10 13:58 micheal's tech 閱讀(876) | 評論 (0)編輯 收藏

            方法1:過該點作一條射線,然后判斷該射線與三條邊的相交情況;  
              方法2:分別連接P點和三個頂點A,B,C,然后判斷矢量PA,PB,PC所夾角之和是否為360度,如果是360度則P在三角形內  
               
              1.    
              #include   <stdio.h>  
              #include   <math.h>  
               
              struct   TPoint  
              {  
              float   x;  
              float   y;  
              };  
               
              float   area(struct   TPoint   p1,struct   TPoint   p2,struct   TPoint   p3){  
              return   fabs((p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y));  
              }  
               
              float   mul(struct   TPoint   p1,struct   TPoint   p2,struct   TPoint   p0){  
              return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));  
              }  
               
              int   inside(struct   TPoint   tr[],struct   TPoint   p){  
              int   i;  
              for   (i=0;i<3;i++)  
              if   (mul(p,tr[i],tr[(i+1)%3])*mul(p,tr[(i+2)%3],tr[(i+1)%3])>0)  
              return   0;  
              return   1;  
              }  
               
              int   inside2(struct   TPoint   tr[],struct   TPoint   p){  
              if   (fabs(area(tr[0],tr[1],tr[2])-  
                area(p,tr[1],tr[2])-  
                area(tr[0],p,tr[2])-  
                area(tr[0],tr[1],p))<1.0e-20)  
              return   1;  
              else  
              return   0;  
              }  
               
              main(){  
              struct   TPoint   tr[3]={{-1,1},{1,0},{3,0}},p={1,2};  
              printf("algorithm   1:");  
              if   (inside(tr,p))  
              printf("In\n");  
              else  
              printf("Out\n");  
              printf("algorithm   2:");  
              if   (inside2(tr,p))  
              printf("In\n");  
              else  
              printf("Out\n");  
              }  
               
              2  
              就是判斷點到三個頂點的夾角之和為2*PI  
              //   返回1   表示在那,0表示在外  
              int   inside3(const   struct   TPoint   tr[],   struct   TPoint   p)  
              {  
              TPoint   p0,p1,p2;  
              p0.x   =   tr[0].x   -   p.x   ;     p0.y   =   tr[0].y   -   p.y;  
              p1.x   =   tr[1].x   -   p.x   ;     p1.y   =   tr[1].y   -   p.y;  
              p2.x   =   tr[2].x   -   p.x   ;     p2.y   =   tr[2].y   -   p.y;  
               
              double   arg1   =   acos((p0.x*p1.x   +   p0.y*p1.y)/sqrt(p0.x*p0.x   +   p0.y*p0.y)/sqrt(p1.x*p1.x+p1.y*p1.y));  
              double   arg2   =   acos((p0.x*p2.x   +   p0.y*p2.y)/sqrt(p0.x*p0.x   +   p0.y*p0.y)/sqrt(p2.x*p2.x+p2.y*p2.y));  
              double   arg3   =   acos((p2.x*p1.x   +   p2.y*p1.y)/sqrt(p2.x*p2.x   +   p2.y*p2.y)/sqrt(p1.x*p1.x+p1.y*p1.y));  
               
              if(   fabs(2*3.1415926-arg1-arg2-arg3)<0.0001   )   return   1;  
              return   0;  
              }  
               

            posted @ 2009-11-04 21:07 micheal's tech 閱讀(1825) | 評論 (0)編輯 收藏

            directhsow filter 里不能用std::vector


            You've got a very odd mix of managed and unmanaged code.  You're definitely missing msvcprtd.lib.  That should knock a good chunk of those errors out.  Project templates are almost always a good idea.

            posted @ 2009-11-04 16:18 micheal's tech 閱讀(184) | 評論 (0)編輯 收藏

                今天dot.kde登了一篇對valgrind的作者 訪談。我作為valgrind的老用戶,當年調程序時獲益很多,在這篇訪談里進一步長了見識,深感有必要把這個優秀的開發工具介紹給諸位。以下內容多翻譯自該訪談(意譯啦)。

            啥是valgrind

                Valgrind是幫助程序員尋找程序里的bug和改進程序性能的工具。程序通過valgrind運行時,valgrind收集各種有用的信息,通過這些信息可以找到程序中潛在的bug和性能瓶頸。
                Valgrind現在提供多個工具,其中最重要的是Memcheck,Cachegrind,Massif和Callgrind。

            Memcheck:

                這個工具可以用來尋找c、c++和fortran程序中內存管理的錯誤。寫c或c++程序時,很多隱藏很深的bug是內存操作上出了問題。而這些在 Memcheck面前都無處遁形(偶當年用的就是這個功能)。Memcheck可以檢查出下列幾種內存操作上的錯誤(大家自查一下有沒有犯過;):
            • 讀寫已經釋放的內存
            • 讀寫內存塊越界(從前或者從后)
            • 使用還未初始化的變量
            • 將無意義的參數傳遞給系統調用
            • 內存泄漏
            • (筆者補充一條,同一個malloc的內存塊釋放多次。當年這么個bug讓我找翻天)      

            Cachegrind:

                這個工具可以提供詳盡的profiling信息。它不光對指令、內存訪問進行計數,更能針對每條指令、每行源代碼、每個函數和每個程序統計cache的不 命中次數。大家應該知道,cache對目前系統的性能有決定性的影響。因此這些信息可以指導程序員調整代碼,最大限度的提高程序性能。
                訪談中提到,valgrind自身利用該工具在過去幾個月內使性能提高了25%-30%。據早先報道,kde的開發team也對valgrind在提高kde性能方面的幫助表示感謝。

            Massif:

                Massif對內存的分配和釋放做profile。程序開發者通過它可以深入了解程序的內存使用行為,從而對內存使用進行優化。這個功能對C++尤其有用(因為C++有很多隱藏的內存分配和釋放)。

            Callgrind:

                Callgrind是一個復雜的工具(復雜到筆者沒看太明白有關它的介紹)。它基于Cachegrind,除了具有Cachegrind的功能外,還可以統計調用帶來的開銷。

            用法:

                Valgrind使用起來非常簡單,你甚至不需要重新編譯你的程序就可以用它。當然如果要達到最好的效果,獲得最準確的信息,還是需要按要求重新編譯一下的。比如在使用memcheck的時候,最好關閉優化選項。

            posted @ 2009-02-02 16:50 micheal's tech 閱讀(796) | 評論 (0)編輯 收藏

            【轉】一個簡單的線程池(c++版)

            #ifndef _ThreadPool_H_
            #define _ThreadPool_H_
            #pragma warning(disable: 4530)
            #pragma warning(disable: 4786)
            #include <cassert>
            #include <vector>
            #include <queue>
            #include <windows.h>
            class ThreadJob  //工作基類
            {
            public:
                //供線程池調用的虛函數
                virtual void DoJob(void *pPara) = 0;
            };
            class ThreadPool
            {
            public:
                //dwNum 線程池規模
                ThreadPool(DWORD dwNum = 4) : _lThreadNum(0), _lRunningNum(0)
                {
                    InitializeCriticalSection(&_csThreadVector);
                    InitializeCriticalSection(&_csWorkQueue);
                    _EventComplete = CreateEvent(0, false, false, NULL);
                    _EventEnd = CreateEvent(0, true, false, NULL);
                    _SemaphoreCall = CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
                    _SemaphoreDel =  CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
                    assert(_SemaphoreCall != INVALID_HANDLE_VALUE);
                    assert(_EventComplete != INVALID_HANDLE_VALUE);
                    assert(_EventEnd != INVALID_HANDLE_VALUE);
                    assert(_SemaphoreDel != INVALID_HANDLE_VALUE);
                    AdjustSize(dwNum <= 0 ? 4 : dwNum);
                }
                ~ThreadPool()
                {
                    DeleteCriticalSection(&_csWorkQueue);
                    CloseHandle(_EventEnd);
                    CloseHandle(_EventComplete);
                    CloseHandle(_SemaphoreCall);
                    CloseHandle(_SemaphoreDel);
                    vector<ThreadItem*>::iterator iter;
                    for(iter = _ThreadVector.begin(); iter != _ThreadVector.end(); iter++)
                    {
                        if(*iter)
                            delete *iter;
                    }
                    DeleteCriticalSection(&_csThreadVector);
                }
                //調整線程池規模
                int AdjustSize(int iNum)
                {
                    if(iNum > 0)
                    {
                        ThreadItem *pNew;
                        EnterCriticalSection(&_csThreadVector);
                        for(int _i=0; _i<iNum; _i++)
                        {
                            _ThreadVector.push_back(pNew = new ThreadItem(this));
                            assert(pNew);
                            pNew->_Handle = CreateThread(NULL, 0, DefaultJobProc, pNew, 0, NULL);
                            assert(pNew->_Handle);
                        }
                        LeaveCriticalSection(&_csThreadVector);
                    }
                    else
                    {
                        iNum *= -1;
                        ReleaseSemaphore(_SemaphoreDel,  iNum > _lThreadNum ? _lThreadNum : iNum, NULL);
                    }
                    return (int)_lThreadNum;
                }
                //調用線程池
                void Call(void (*pFunc)(void  *), void *pPara = NULL)
                {
                    assert(pFunc);
                    EnterCriticalSection(&_csWorkQueue);
                    _JobQueue.push(new JobItem(pFunc, pPara));
                    LeaveCriticalSection(&_csWorkQueue);
                    ReleaseSemaphore(_SemaphoreCall, 1, NULL);
                }
                //調用線程池
                inline void Call(ThreadJob * p, void *pPara = NULL)
                {
                    Call(CallProc, new CallProcPara(p, pPara));
                }
                //結束線程池, 并同步等待
                bool EndAndWait(DWORD dwWaitTime = INFINITE)
                {
                    SetEvent(_EventEnd);
                    return WaitForSingleObject(_EventComplete, dwWaitTime) == WAIT_OBJECT_0;
                }
                //結束線程池
                inline void End()
                {
                    SetEvent(_EventEnd);
                }
                inline DWORD Size()
                {
                    return (DWORD)_lThreadNum;
                }
                inline DWORD GetRunningSize()
                {
                    return (DWORD)_lRunningNum;
                }
                bool IsRunning()
                {
                    return _lRunningNum > 0;
                }
            protected:
                //工作線程
                static DWORD WINAPI DefaultJobProc(LPVOID lpParameter = NULL)
                {
                    ThreadItem *pThread = static_cast<ThreadItem*>(lpParameter);
                    assert(pThread);
                    ThreadPool *pThreadPoolObj = pThread->_pThis;
                    assert(pThreadPoolObj);
                    InterlockedIncrement(&pThreadPoolObj->_lThreadNum);
                    HANDLE hWaitHandle[3];
                    hWaitHandle[0] = pThreadPoolObj->_SemaphoreCall;
                    hWaitHandle[1] = pThreadPoolObj->_SemaphoreDel;
                    hWaitHandle[2] = pThreadPoolObj->_EventEnd;
                    JobItem *pJob;
                    bool fHasJob;
                    for(;;)
                    {
                        DWORD wr = WaitForMultipleObjects(3, hWaitHandle, false, INFINITE);
                        //響應刪除線程信號
                        if(wr == WAIT_OBJECT_0 + 1) 
                            break;
                        //從隊列里取得用戶作業
                        EnterCriticalSection(&pThreadPoolObj->_csWorkQueue);
                        if(fHasJob = !pThreadPoolObj->_JobQueue.empty())
                        {
                            pJob = pThreadPoolObj->_JobQueue.front();
                            pThreadPoolObj->_JobQueue.pop();
                            assert(pJob);
                        }
                        LeaveCriticalSection(&pThreadPoolObj->_csWorkQueue);
                        //受到結束線程信號確定是否結束線程(結束線程信號&& 是否還有工作)
                        if(wr == WAIT_OBJECT_0 + 2 && !fHasJob) 
                            break;
                        if(fHasJob && pJob)
                        {
                            InterlockedIncrement(&pThreadPoolObj->_lRunningNum);
                            pThread->_dwLastBeginTime = GetTickCount();
                            pThread->_dwCount++;
                            pThread->_fIsRunning = true;
                            pJob->_pFunc(pJob->_pPara); //運行用戶作業
                            delete pJob;
                            pThread->_fIsRunning = false;
                            InterlockedDecrement(&pThreadPoolObj->_lRunningNum);
                        }
                    }
                    //刪除自身結構
                    EnterCriticalSection(&pThreadPoolObj->_csThreadVector);
                pThreadPoolObj->_ThreadVector.erase(find(pThreadPoolObj->_ThreadVector.begin(), pThreadPoolObj->_ThreadVector.end(), pThread));
                    LeaveCriticalSection(&pThreadPoolObj->_csThreadVector);
                    delete pThread;
                    InterlockedDecrement(&pThreadPoolObj->_lThreadNum);
                    if(!pThreadPoolObj->_lThreadNum)  //所有線程結束
                        SetEvent(pThreadPoolObj->_EventComplete);
                    return 0;
                }
                //調用用戶對象虛函數
                static void CallProc(void *pPara)
                {
                    CallProcPara *cp = static_cast<CallProcPara *>(pPara);
                    assert(cp);
                    if(cp)
                    {
                        cp->_pObj->DoJob(cp->_pPara);
                        delete cp;
                    }
                }
                //用戶對象結構
                struct CallProcPara 
                {
                    ThreadJob* _pObj;//用戶對象
                    void *_pPara;//用戶參數
                    CallProcPara(ThreadJob* p, void *pPara) : _pObj(p), _pPara(pPara) { };
                };
                //用戶函數結構
                struct JobItem
                {
                    void (*_pFunc)(void  *);//函數
                    void *_pPara; //參數
                    JobItem(void (*pFunc)(void  *) = NULL, void *pPara = NULL) : _pFunc(pFunc), _pPara(pPara) { };
                };
                //線程池中的線程結構
                struct ThreadItem
                {
                    HANDLE _Handle; //線程句柄
                    ThreadPool *_pThis;  //線程池的指針
                    DWORD _dwLastBeginTime; //最后一次運行開始時間
                    DWORD _dwCount; //運行次數
                    bool _fIsRunning;
                    ThreadItem(ThreadPool *pthis) : _pThis(pthis), _Handle(NULL), _dwLastBeginTime(0), _dwCount(0), _fIsRunning(false) { };
                    ~ThreadItem()
                    {
                        if(_Handle)
                        {
                            CloseHandle(_Handle);
                            _Handle = NULL;
                        }
                    }
                };
                std::queue<JobItem *> _JobQueue;  //工作隊列
                std::vector<ThreadItem *>  _ThreadVector; //線程數據
                CRITICAL_SECTION _csThreadVector, _csWorkQueue; //工作隊列臨界, 線程數據臨界
                HANDLE _EventEnd, _EventComplete, _SemaphoreCall, _SemaphoreDel;//結束通知, 完成事件, 工作信號,刪除線程信號
                long _lThreadNum, _lRunningNum; //線程數, 運行的線程數
            };
            #endif //_ThreadPool_H_

            使用說明1:

            調用方法

            void threadfunc(void *p)
            {
                 YourClass* yourObject = (YourClass*)    p;
             //
            }
             ThreadPool tp;
             for(i=0; i<100; i++)
              tp.Call(threadfunc);
            ThreadPool tp(20);//20為初始線程池規模
             tp.Call(threadfunc, lpPara);

            使用時注意幾點:

            1. ThreadJob  沒什么用,直接寫線程函數吧。 

            2. 線程函數(threadfunc)的入口參數void* 可以轉成自定義的類型對象,這個對象可以記錄下線程運行中的數據,并設置線程當前狀態,以此與線程進行交互。

            3. 線程池有一個EndAndWait函數,用于讓線程池中所有計算正常結束。有時線程池中的一個線程可能要運行很長時間,怎么辦?可以通過線程函數threadfunc的入口參數對象來處理,比如:

            class YourClass 
            {
              int cmd; // cmd = 1是上線程停止計算,正常退出。
            };
            threadfunc(void* p) {
              YourClass* yourObject = (YourClass*)p;
              while (true) {
                // do some calculation
                if (yourClass->cmd == 1)
                  break;
              }
            }

            在主線程中設置yourClass->cmd = 1,該線程就會自然結束。

            使用說明2:

            Code
            void threadfunc(void *p)
            {
             //
            }
             ThreadPool tp;
             for(i=0; i<100; i++)
              tp.Call(threadfunc);
             ThreadPool tp(20);//20為初始線程池規模
             tp.Call(threadfunc, lpPara);
             tp.AdjustSize(50);//增加50
             tp.AdjustSize(-30);//減少30

             

            class MyThreadJob : public ThreadJob //線程對象從ThreadJob擴展
            {
            public:
             virtual void DoJob(void *p)//自定義的虛函數
             {
              //.
             }
            };
             MyThreadJob mt[10];
             ThreadPool tp;
             for(i=0; i<100 i++)
              tp.Call(mt + i);//tp.Call(mt + i, para);

            posted @ 2009-02-02 16:28 micheal's tech 閱讀(6064) | 評論 (0)編輯 收藏

            多線程同步機制摘要

            Posted on 2007-04-03 19:34 kk 閱讀(1306) 評論(0)  編輯 收藏 引用 所屬分類: IT
              Critical Section

            Critical section(臨界區)用來實現“排他性占有”。適用范圍是單一進程的各線程之間。它是:

            ·         一個局部性對象,不是一個核心對象。

            ·         快速而有效率。

            ·         不能夠同時有一個以上的critical section被等待。

            ·         無法偵測是否已被某個線程放棄。

            Mutex

            Mutex是一個核心對象,可以在不同的線程之間實現“排他性占有”,甚至幾十那些現成分屬不同進程。它是:

            ·         一個核心對象。

            ·         如果擁有mutex的那個線程結束,則會產生一個“abandoned”錯誤信息。

            ·         可以使用Wait…()等待一個mutex。

            ·         可以具名,因此可以被其他進程開啟。

            ·         只能被擁有它的那個線程釋放(released)。

            Semaphore

            Semaphore被用來追蹤有限的資源。它是:

            ·         一個核心對象。

            ·         沒有擁有者。

            ·         可以具名,因此可以被其他進程開啟。

            ·         可以被任何一個線程釋放(released)。

            Event Object

            Event object通常使用于overlapped I/O,或用來設計某些自定義的同步對象。它是:

            ·         一個核心對象。

            ·         完全在程序掌控之下。

            ·         適用于設計新的同步對象。

            ·         “要求蘇醒”的請求并不會被儲存起來,可能會遺失掉。

            ·         可以具名,因此可以被其他進程開啟。

            Interlocked Variable

            如果Interlocked…()函數被使用于所謂的spin-lock,那么他們只是一種同步機制。所謂spin-lock是一種busy loop,被預期在極短時間內執行,所以有最小的額外負擔(overhead)。系統核心偶爾會使用他們。除此之外,interlocked variables主要用于引用技術。他們:

            ·         允許對4字節的數值有些基本的同步操作,不需動用到critical section或mutex之類。

            ·         在SMP(Symmetric Multi-Processors)操作系統中亦可有效運作。


            posted @ 2009-02-02 14:35 micheal's tech 閱讀(719) | 評論 (0)編輯 收藏

            高性能服務器的多線程策略


            (一)線程數量與線程池模型
              參見:high-performance server design. http://pl.atyp.us/content/tech/servers.html

              頻繁的上下文切換,會導致系統性能嚴重下降,而產生過多的切換大致有兩個原因:
            1)過多的線程數量。這會使系統性能呈指數級的下降。對于每連接一個線程的系統而言,這也是為什么性能會變差的原因。一個具有可伸縮性的系統,它的唯一 可行的選擇,就是限制運行線程的數量。一般而言,這個值應該小于或等于處理器的數目。(說明,在boost網絡庫asio提供的example中,有一個 關于這種實現的很好的例子)
              2)所使用的線程池及事件模型。最簡單的一種模型通常是這個樣子:一個偵聽線程異步地接收請求,并在隊列中進行緩 沖。另外一組工作者線程則負責處理這些請求。這是一個不錯的模型,缺點就是每處理一個請求一般要經過兩次線程切換(加上對請求的回復)。為了避免這種缺 點,一個線程就必須具備偵聽者和工作者兩種角色,可以采用稱之謂“領導者/跟隨者”的模型。一個線程作為領導者,來進行監聽,當收到請求時,它選出一個跟 隨者線程作為新的領導者進行偵聽,自己則對請求進行處理,結束后,到跟隨者隊列中進行等待。

            (二)多線程的內存池優化

            普通的內存池一旦應用到多線程中,都面臨著鎖競爭的問題,在stlport所做的對于字符串性能的測試中,當使用兩個線程時,它所使用的內存池 node_allocator性能已經出現明顯的下降。所以對于多線程而言,一個線程一個內存池是一個很好的選擇。要實現這種設計,面臨的第一個問題,是 內存塊的跨線程使用問題,即一個內存塊,可能在A線程中申請,但可能在B線程中釋放。
              在GCC的STL實現libstdc++中,有一個多線程內存池的實現(mt_allocator)。它是node_allocator(現在叫pool_allocator) 的多線程版本。它還有一個優點就是所有參數都是可配置的。
              它的設計思路如下:每個線程一個內存池,同時還有一個全局的內存池。每個線程可以訪問自己的內存池,同時可在鎖保護下訪問全局內存池。申請的每一個內存塊中,都有一個線程ID,以標明是從哪個線程中申請的。
              申請過程:首先向所在線程申請,若本線程沒有空閑塊,則向全局內存池申請。
              釋放過程:直接歸還到本線程的空閑鏈中。還有一個問題,為了防止線程內存池之間的不均衡,或者某一個線程中的空閑鏈過長,可以設置一個水位標,當超過這個水位標時,把釋放的內存直接歸還到全局內存池中。

            posted @ 2009-01-12 16:38 micheal's tech 閱讀(393) | 評論 (0)編輯 收藏


            "placement new"? Embarrassed它 到底是什么東東呀?我也是最近幾天才聽說,看來對于C++我還差很遠呀!placement new 是重載operator new的一個標準、全局的版本,它不能被自定義的版本代替(不像普通的operator new和operator delete能夠被替換成用戶自定義的版本)。

            它的原型如下:
            void *operator new( size_t, void *p ) throw()  { return p; }

            首先我們區分下幾個容易混淆的關鍵詞:new、operator new、placement new
            new和delete操作符我們應該都用過,它們是對中的內存進行申請和釋放,而這兩個都是不能被重載的。要實現不同的內存分配行為,需要重載operator new,而不是new和delete。I dont know

            看如下代碼:
            class MyClass {…};
            MyClass * p=new MyClass;

            這里的new實際上是執行如下3個過程:


            1. 調用operator new分配內存 ;2. 調用構造函數生成類對象;3. 返回相應指針。

            operator new就像operator+一樣,是可以重載的,但是不能在全局對原型為void operator new(size_t size)這個原型進行重載,一般只能在類中進行重載。如果類中沒有重載operator new,那么調用的就是全局的::operator new來完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重載的,一般你重載的其中一個,那么最后把其余的三個都重載一遍。

            至于placement new才是本文的重點。其實它也只是operator new的一個重載的版本,只是我們很少用到它。如果你想在已經分配的內存中創建一個對象,使用new時行不通的。也就是說placement new允許你在一個已經分配好的內存中(棧或者堆中)構造一個新的對象。原型中void*p實際上就是指向一個已經分配好的內存緩沖區的的首地址。

            我們知道使用new操作符分配內存需要在堆中查找足夠大的剩余空間,這個操作速度是很慢的,而且有可能出現無法分配內存的異常(空間不夠)。 placement new就可以解決這個問題。我們構造對象都是在一個預先準備好了的內存緩沖區中進行,不需要查找內存,內存分配的時間是常數;而且不會出現在程序運行中途 出現內存不足的異常。所以,placement new非常適合那些對時間要求比較高,長時間運行不希望被打斷的應用程序。

            使用方法如下:
            1. 緩沖區提前分配
            可以使用堆的空間,也可以使用棧的空間,所以分配方式有如下兩種:
            class MyClass {…};
            char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ; 或者char buf[N*sizeof(MyClass)+ sizeof(int) ];

            2. 對象的構造
            MyClass * pClass=new(buf) MyClass;

            3. 對象的銷毀
            一旦這個對象使用完畢,你必須顯式的調用類的析構函數進行銷毀對象。但此時內存空間不會被釋放,以便其他的對象的構造。
            pClass->~MyClass();

            4. 內存的釋放
            如果緩沖區在堆中,那么調用delete[] buf;進行內存的釋放;如果在棧中,那么在其作用域內有效,跳出作用域,內存自動釋放。

            注意:

            • 在C++標準中,對于placement operator new []有如下的說明: placement operator new[] needs implementation-defined amount of additional storage to save a size of array. 所以我們必須申請比原始對象大小多出sizeof(int)個字節來存放對象的個數,或者說數組的大小。
            • 使用方法第二步中的new才是placement new,其實是沒有申請內存的,只是調用了構造函數,返回一個指向已經分配好的內存的一個指針,所以對象銷毀的時候不需要調用delete釋放空間,但必須調用析構函數銷毀對象。

            posted @ 2009-01-08 20:56 micheal's tech 閱讀(1599) | 評論 (0)編輯 收藏

            http://www.shnenglu.com/dyj057/archive/2005/09/20/346.html

            大家都知道,在用C++來實現Singleton模式的時候通常把構造函數聲明為私有的或者保護的。同時聲明一個公有的靜態的偽構造函數,通過它來調用真正的構造函數。在實現這個偽構造函數的時候通常有兩種方式:  
              class   Singleton;  
               
              static   Singleton&   Singleton:;fakeSingleton()  
              {  
                      static   Singleton   s;  
                      return   s;  
              }  
              第二種方式:  
              class   Singleton{  
              public:  
              static   Singleton*   fakeSingleton();  
              ...  
              private:  
              Singleton();  
              static   Singleton   *   _instance;  
              }  
              Singleton*   Singleton::fakesinketon()  
              {  
                    if(   _instance==NULL)  
                              _instance=new   Singleton();  
                      return   _instance;  
              }  
              對于這兩種方式我覺得第一種更好一些,理由是,如果有兩個以上的線程同時訪問偽構造函數的時候有可能同時進入if   控制塊,這樣就有可能產生兩個實例!!因此必須采用特殊的保護機制來控制同步。而第一種方式不存在這樣的問題。  
               
              請高手指點!我不明白的是,為什么書上的例子還較多的采用第二種方法?莫非它有自己的優勢??  
               

            posted @ 2009-01-06 16:06 micheal's tech 閱讀(1577) | 評論 (7)編輯 收藏

            貪心法的基本思路:  
               
              從問題的某一個初始解出發逐步逼近給定的目標,以盡可能快的地求得更好的解。當達到某算法中的某一步不能再繼續前進時,算法停止。  
              該算法存在問題:  
              1.   不能保證求得的最后解是最佳的;  
              2.   不能用來求最大或最小解問題;  
              3.   只能求滿足某些約束條件的可行解的范圍。 實現該算法的過程:  
              從問題的某一初始解出發;
              
              while   能朝給定總目標前進一步   do  
              求出可行解的一個解元素;  
              由所有解元素組合成問題的一個可行解

            貪心算法最經典的例子,給錢問題。  
              比如中國的貨幣,只看元,有1元2元5元10元20、50、100  
               
              如果我要16元,可以拿16個1元,8個2元,但是怎么最少呢?  
              如果用貪心算,就是我每一次拿那張可能拿的最大的。  
              比如16,我第一次拿20拿不起,拿10元,OK,剩下6元,再拿個5元,剩下1元  
              也就是3張   10、5、1。  
               
              每次拿能拿的最大的,就是貪心。  
               
              但是一定注意,貪心得到的并不是最優解,也就是說用貪心不一定是拿的最少的張數  
              貪心只能得到一個比較好的解,而且貪心算法很好想得到。  
              再注意,為什么我們的錢可以用貪心呢?因為我們國家的錢的大小設計,正好可以使得貪心算法算出來的是最優解(一般是個國家的錢幣都應該這么設計)。如果設計成別的樣子情況就不同了  
              比如某國的錢幣分為   1元3元4元  
              如果要拿6元錢   怎么拿?貪心的話   先拿4   再拿兩個1     一共3張錢  
              實際最優呢?   兩張3元就夠了  


            求最優解的問題,從根本上說是一種對解空間的遍歷。最直接的暴力分析容易得到,最優解的解空間通常都是以指數階增長,因此暴力窮舉都是不可行的。
            最優解問題大部分都可以拆分成一個個的子問題,把解空間的遍歷視作對子問題樹的遍歷,則以某種形式對樹整個的遍歷一遍就可以求出最優解,如上面的分析,這是不可行的。
            貪心和動態規劃本質上是對子問題樹的一種修剪。兩種算法要求問題都具有的一個性質就是“子問題最優性”。即,組成最優解的每一個子問題的解,對 于這個子問題本身肯定也是最優的。如果以自頂向下的方向看問題樹(原問題作根),則,我們每次只需要向下遍歷代表最優解的子樹就可以保證會得到整體的最優 解。形象一點說,可以簡單的用一個值(最優值)代表整個子樹,而不用去求出這個子樹所可能代表的所有值。
            動態規劃方法代表了這一類問題的一般解法。我們自底向上(從葉子向根)構造子問題的解,對每一個子樹的根,求出下面每一個葉子的值,并且以其中 的最優值作為自身的值,其它的值舍棄。動態規劃的代價就取決于可選擇的數目(樹的叉數)和子問題的的數目(樹的節點數,或者是樹的高度?)。
            貪心算法是動態規劃方法的一個特例。貪心特在,可以證明,每一個子樹的根的值不取決于下面葉子的值,而只取決于當前問題的狀況。換句話說,不需 要知道一個節點所有子樹的情況,就可以求出這個節點的值。通常這個值都是對于當前的問題情況下,顯而易見的“最優”情況。因此用“貪心”來描述這個算法的 本質。由于貪心算法的這個特性,它對解空間樹的遍歷不需要自底向上,而只需要自根開始,選擇最優的路,一直走到底就可以了。這樣,與動態規劃相比,它的代 價只取決于子問題的數目,而選擇數目總為1。


            posted @ 2008-11-18 11:20 micheal's tech 閱讀(3520) | 評論 (0)編輯 收藏

            僅列出標題
            共8頁: 1 2 3 4 5 6 7 8 
            久久99国产精品成人欧美| 亚洲精品高清国产一线久久| 国产精品久久久福利| 久久精品成人免费看| 欧美粉嫩小泬久久久久久久| 亚洲综合熟女久久久30p| 伊人久久大香线蕉精品| 亚洲精品无码久久毛片| 久久综合狠狠色综合伊人| 久久综合精品国产一区二区三区| 免费无码国产欧美久久18| 久久国产精品一区二区| 伊人久久一区二区三区无码| 精品久久久久久亚洲| 久久婷婷五月综合97色直播| 蜜桃麻豆www久久| 狠狠色婷婷久久一区二区三区| 色播久久人人爽人人爽人人片aV | 久久天天日天天操综合伊人av| 中文字幕久久波多野结衣av| 国内精品久久久久久久涩爱| 久久AV高清无码| 久久久噜噜噜久久熟女AA片| 尹人香蕉久久99天天拍| 精品久久久久国产免费| 久久精品男人影院| 久久精品水蜜桃av综合天堂| 亚洲Av无码国产情品久久| 久久久青草久久久青草| 久久91精品国产91久久户| 久久人人爽人人爽人人AV| 久久久久波多野结衣高潮| 久久久久久久精品成人热色戒| 久久乐国产精品亚洲综合| 久久精品亚洲男人的天堂| 国产福利电影一区二区三区,免费久久久久久久精 | 色综合久久88色综合天天| 国产91色综合久久免费分享| 91久久婷婷国产综合精品青草| 久久久国产打桩机| 天天躁日日躁狠狠久久|