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

    }

 

2010年9月18日 星期六

[Java] 貪食蛇

這是一個非常簡單的畫出移動及按鍵的控制..

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import javax.swing.*;


public class Snake extends JFrame implements Runnable {

  private PaintPanel paintPanel = new PaintPanel();

  private boolean isRunning = true;

  private long[] sleepTime  = {500, 400, 300, 200, 100};

  private int dir = KeyEvent.VK_RIGHT;

  static Snake s = null;

  private LinkedList<Point> snakeList = new LinkedList<Point>();

  private int resolution = 20;

  public Snake() {

    super("Java Snake");

    setSize(500, 500);

    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

    setLocation(((int)dim.getWidth() - 500) / 2, ((int)dim.getHeight() - 500) / 2);

    initComponent();

    initSnake();

    setVisible(true);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

  }

  private void initSnake() {

    snakeList.add(new Point(7,0));

    snakeList.add(new Point(6,0));

    snakeList.add(new Point(5,0));

    snakeList.add(new Point(4,0));

    snakeList.add(new Point(3,0));

    snakeList.add(new Point(2,0));

    snakeList.add(new Point(1,0));

    snakeList.add(new Point(0,0));

  }

  private void initComponent() {

    setLayout(new BorderLayout());

    add(paintPanel);

    addKeyListener(new SnakeKeyListener());

    addComponentListener(new ComponentListener() {

      public void componentHidden(ComponentEvent arg0) {

      }

      public void componentMoved(ComponentEvent arg0) {

      }

      public void componentResized(ComponentEvent arg0) {

        Dimension d = s.getSize();

        if(d.width <= 500) s.setSize(500, 500);

        if(d.height <= 500) s.setSize(500, 500);

      }

      public void componentShown(ComponentEvent arg0) {

      }

    });


  }

  public void run() {

    while(isRunning) {

      try {

        Thread.sleep(sleepTime[0]);

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

      checkBoundary();

      moveSnake();

      paintPanel.repaint();

    }

  }

  private void moveSnake() {

    Point p = snakeList.get(0);

    Point newPoint = null;

    switch(dir) {

      case KeyEvent.VK_RIGHT:

        newPoint = new Point(p.x + 1, p.y);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_LEFT:

        newPoint = new Point(p.x - 1, p.y);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_UP:

        newPoint = new Point(p.x, p.y - 1);

        snakeList.addFirst(newPoint);

        break;

      case KeyEvent.VK_DOWN:

        newPoint = new Point(p.x, p.y + 1);

        snakeList.addFirst(newPoint);

        break;

    }

    snakeList.removeLast();

  }

  private void checkBoundary() {

    

  }

  public static void main(String[] args) {

      s = new Snake();

    Thread d = new Thread(s);

    d.start();


  }

  private final class SnakeKeyListener extends KeyAdapter {

    public void keyPressed(KeyEvent arg0) {

      int keyDir = arg0.getKeyCode();

      if(keyDir != KeyEvent.VK_UP && keyDir != KeyEvent.VK_DOWN &&

          keyDir != KeyEvent.VK_RIGHT && keyDir != KeyEvent.VK_LEFT) {

        return;

      }

      if((dir == KeyEvent.VK_UP && keyDir == KeyEvent.VK_DOWN) || 

         (dir == KeyEvent.VK_DOWN && keyDir == KeyEvent.VK_UP) ||

         (dir == KeyEvent.VK_RIGHT && keyDir == KeyEvent.VK_LEFT) ||

         (dir == KeyEvent.VK_LEFT && keyDir == KeyEvent.VK_RIGHT)) {

        System.out.println("return");

        return;

      }

      dir = keyDir;

    }

  }

  private final class PaintPanel extends JPanel {


    public PaintPanel() {

      setBackground(Color.DARK_GRAY);

    }

    public void paint(Graphics g) {

      CleanBackground(g);

      PaintSnake(g);

    }

    private void PaintSnake(Graphics g) {

      Dimension d = null;

      d = getSize(d);

      for(int i = 0; i < snakeList.size(); ++i) {

        g.setColor(new Color(0, 255 - i*(255 / (snakeList.size())), 0));

        Point p = snakeList.get(i);

        g.fill3DRect(

            p.x*(int)(d.width / resolution), 

            p.y*(int)(d.height / resolution), 

            d.width / resolution, d.height / resolution, 

            true

            );

      }

    }

    private void CleanBackground(Graphics g) {

      Dimension d = null;

      d = getSize(d);

      g.setColor(Color.RED);

      g.fillRect(0, 0, d.width, d.height);

      g.setColor(Color.DARK_GRAY);

      for(int i = 0; i < d.width / resolution; ++i) {

        for(int j = 0; j < d.height / resolution; ++j){

          g.fill3DRect(

              i*(int)(d.width / resolution), 

              j*(int)(d.height / resolution), 

              d.width / resolution, 

              d.height / resolution, 

              true);

        }

      }

    }

  }

}