2010年11月28日 星期日

在c/c++裡盡可能的使用forward declaration

這個方法是讓你不要在.h檔裡include了一堆其他的.h檔, 好處是當其.h修改時, 並不會影響到太多的c.pp須要重新compile, 某方面也加快了build project的速度, 其最大的好處是, .h檔不會太雜亂.

作法如下(參考http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml), 其實大家都知道, 但很少人做到..

Suppose you want to define a new class B that uses objects of class A.

  1. B only uses references or pointers to A. Use forward declaration then : you don't need to include <A.h>. This will in turn speed a little bit the compilation.
      class A ;
      
      class B {
        private:
          A* fPtrA ;
        public:
          void mymethod(const& A) const ;
      } ;
      
  2. B derives from A or B explicitely (or implicitely) uses objects of class A. You then need to include <A.h>
      #include <A.h>
      
      class B : public A {
      
      } ;
      
      class C {
        private:
          A fA ;
        public:
          void mymethod(A par) ;   
      }

 

盡可能的使用forward declaration

這是個原則性問題, 但通常我們不會寫, 我們會在一個.h檔裡include其他的.h檔, 這是不好的作法, 因為你很有可能改了一個.h檔之後, 造成很多的.cpp須要重build...

所以我們可以怎麼做呢?

 

2010年11月26日 星期五

WaitForSingleObject卻無法跳出!?

這是一個很好的sample code

 

UINT fnThread0(LPVOID p)

{

ThreadPara* pPara = (ThreadPara*)p;

while (pPara->bStart)

{

clock_t c1 = clock();

if ( c1 % 1000 < 250 * 1 )

pPara->pDlg->GetDlgItem(IDC_TEXT1)->SetWindowText("\\");

else if ( c1 % 1000 < 250 * 2 )

pPara->pDlg->GetDlgItem(IDC_TEXT1)->SetWindowText("|");

else if ( c1 % 1000 < 250 * 3 )

pPara->pDlg->GetDlgItem(IDC_TEXT1)->SetWindowText("/");

else 

pPara->pDlg->GetDlgItem(IDC_TEXT1)->SetWindowText("--");

 

Sleep(250);

}

pPara->pDlg->GetDlgItem(IDC_TEXT1)->SetWindowText("Stop");

return 1000;

}

 

void CThreadDlg::OnBnClickedOk()

{

m_ThreadPara.pDlg = this;

if ( m_ThreadPara.bStart == false )

{

// begin thread

m_ThreadPara.bStart = true;

m_pThreadHandle = AfxBeginThread( fnThread0, &m_ThreadPara );

}

else

{

// close thread

m_ThreadPara.bStart = false;

        Sleep(1000);

::WaitForSingleObject( m_pThreadHandle->m_hThread, INFINITE );

}

Sleep(0);

}

這段code哪裡出了問題呢?其實大家會認為我設了flag而且有等這個thread結束就沒問題了, 但是請看下面的圖



所以, 在設定falsg為false之後, 立即進到wait for single object, 而這時worker thread還沒有完成, 所以進到了更新UI的動作, 但main thread(UI thread)已被WaitForSingleObject block住了, 所以此時worker thread也在等main thread, 於是乎兩個互等, 造成的dead lock...

如何避開呢?其實大家如果記得windows API裡還有一個叫做PostMessage的東西, 建一個自己的message type, 然後寫一個function去處理吧, 這樣一來就不會有這個情形發生...

感謝Jame提供的sample code..這是一個非常好的例子...

 

2010年11月23日 星期二

不用使用任何額外的記憶體, 就把字串反轉!!

字串反轉, 這是個老問題, 隨手寫來也是很快

char* t = "123456789\0";

char* l = new char[strlen(t)];

for(size_t i = 0; i < strlen(t); ++i) {

    l[strlen(t)-1-i] = t[i]; // copy t to l

}

 

沒啥大問題, 但..有沒有辦法不使用額外的記憶體就把字串copy完呢?看下面的程式

 

    char str[10] = {'1', '2', '3', '4', '5', '6', '7'};

    char *a, *b, c;

    a = b = str;

    while (*b) 

        b++; 

    --b;

    while (b >a) {

        c = *a;

        *a++ = *b;

        *b-- = c;

    }

這樣不是用了兩個pointer及一個c嗎?其實在打開compiler最佳化後, 來看一下組合語言

int _tmain(int argc, _TCHAR* argv[])

{

00401000  sub         esp,10h 

00401003  mov         eax,dword ptr [___security_cookie (403000h)] 

00401008  xor         eax,esp 

0040100A  mov         dword ptr [esp+0Ch],eax 

    char str[10] = {'1', '2', '3', '4', '5', '6', '7'};

0040100E  xor         eax,eax 

00401010  mov         dl,31h 

    char *f, *t, c;    /// 這裡並沒有allocate任何記憶體

    f = t = str;

    while (*t) 

00401012  test        dl,dl 

00401014  mov         word ptr [esp+7],ax 

00401019  mov         byte ptr [esp+9],al 

0040101D  lea         eax,[esp] 

00401020  mov         byte ptr [esp],dl 

00401023  mov         byte ptr [esp+1],32h 

00401028  mov         byte ptr [esp+2],33h 

0040102D  mov         byte ptr [esp+3],34h 

00401032  mov         byte ptr [esp+4],35h 

00401037  mov         byte ptr [esp+5],36h 

0040103C  mov         byte ptr [esp+6],37h 

00401041  mov         ecx,eax 

00401043  je          wmain+4Dh (40104Dh) 

        t++;              //使用t時是直接使用eax

00401045  add         eax,1 

00401048  cmp         byte ptr [eax],0 

0040104B  jne         wmain+45h (401045h) 

    --t;

0040104D  sub         eax,1 

 

    while (t > f) {

00401050  lea         edx,[esp] 

00401053  cmp         eax,edx 

00401055  jbe         wmain+6Bh (40106Bh) 

00401057  push        ebx  

        c = *f;

        *f++ = *t;       /// 使用f時是使用ebx

00401058  mov         bl,byte ptr [eax] 

0040105A  mov         dl,byte ptr [ecx] 

0040105C  mov         byte ptr [ecx],bl 

        *t-- = c;         /// 使用c時是使用ecx

0040105E  mov         byte ptr [eax],dl 

00401060  add         ecx,1 

00401063  sub         eax,1 

00401066  cmp         eax,ecx 

00401068  ja          wmain+58h (401058h) 

0040106A  pop         ebx  

    }

return 0;

}

 

所以..完全沒用到記憶體耶..XD

2010年11月22日 星期一

利用boost shared_mutex來實作read / write lock

 

How to implement a mulltiple read single write locker? This is the sample code by using boost shared_mutex. The other classes are using shared_lock, upgrade_lock and upgrade_to_unique_lock.

 

using namespace boost;


typedef boost::shared_mutex rwmutex;

typedef boost::shared_lock<rwmutex> readLock; 

typedef boost::upgrade_lock<rwmutex> upgradeLock;

typedef boost::upgrade_to_unique_lock<rwmutex> writeLock;

 

 

rwmutex  _rwmutex; 

 void readOnly() {

    {

        readLock rdlock(_rwmutex);

        ... do something ... 

    }

 

void writeOnly() {

    {
        upgradeLock lock(_rwmutex);

        writeLock wLock(lock);

        ... do something

    }