Error

C++博客 首页 新随笔 联系 聚合 管理
  217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks

#

M{D%1Y@56QFN6COBX(@Y6BR

posted @ 2013-03-11 15:58 Enic 阅读(139) | 评论 (0)编辑 收藏

// learn_boost_asio.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <memory>
#include <boost/asio.hpp>
#include <boost/timer.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
namespace asio = boost::asio;
namespace posix_time = boost::posix_time ;
// 1.同步定时器使用
void LeanrHowToUseSynchronouslyTimer()
{
asio::io_service io;
asio::deadline_timer deadLineTimer(io, posix_time::seconds(3));
boost::timer timerTestDeadLineTimer;
timerTestDeadLineTimer.restart();
deadLineTimer.wait();
double dTime = timerTestDeadLineTimer.elapsed();
std::cout << dTime << std::endl;
}
////////~
// 2.异步定时器使用
class CSomeObject
{
public:
CSomeObject(asio::io_service& ioService) :
   m_deadLineTimer(ioService)
{
}
public:
void Test()
{
m_deadLineTimer.expires_from_now(boost::posix_time::seconds(3));
m_timerTestDeadTimer.restart();
m_deadLineTimer.async_wait(
boost::bind(&CSomeObject::TimerHandler, this, asio::placeholders::error));
}
public:
void TimerHandler(const boost::system::error_code&)
{
double dTime = m_timerTestDeadTimer.elapsed();
std::cout << "time passed: " << dTime << std::endl;
}
private:
boost::timer m_timerTestDeadTimer;
asio::deadline_timer m_deadLineTimer;
};
void LearnHowToUseAsynchronouslyTimer()
{
asio::io_service ioService;
CSomeObject obj(ioService);
obj.Test();
asio::io_service::work* pWork = new asio::io_service::work(ioService);
std::auto_ptr<asio::io_service::work> spWork(pWork);
ioService.run();
//spWork.reset(); // Allow run() to exit. 
}
//////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
LearnHowToUseAsynchronouslyTimer();
return 0;
}
posted @ 2013-03-08 18:04 Enic 阅读(781) | 评论 (0)编辑 收藏

从GameDemo.cpp看起

 

1回顾通常的sdk窗口程序流程:注册窗口-创建窗口-显示窗口-启动消息循环

 

1.1注册窗口类

Duilib中最平凡的真实窗口类是:CWindowWnd,关于窗口注册提供了两个函数,严格的说应该是几个:

RegisterWindowClass()

RegisterSuperclass()

GetWindowClassName()

GetSuperClassName()

GetClassStyle()

在我的理解中,后面两个虚函数的意义应该是:上面这些接口分两组,一组是用于正常注册使用,一组用于扩展。

使用的时候用自定义的窗口对象从CWindowWnd继承下来,然后定制自己需要的window class

1.2创建窗口

    CGameFrameWnd* pFrame = new CGameFrameWnd();
    if( pFrame == NULL ) return 0;
    pFrame->Create(NULL, _T(""), UI_WNDSTYLE_FRAME, 0L, 0, 0, 1024, 738);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

CWindowWnd带有mfc CWnd类似的Create接口用于创建窗口,同事注册窗口类也通过虚函数的方式延后到子类实现,super机制(如果有super优先注册)也带进来。

    if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
    if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

1.3显示窗口

和sdk是一样的

::ShowWindow(*pFrame, SW_SHOWMAXIMIZED);

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } 1.4消息循环

CPaintManagerUI::MessageLoop();
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

1.5消息回调函数

在窗口类注册的时候应该要注册窗口回调函数指针,Duilib中默认是在CWindowWnd::RegisterWindow注册:

bool CWindowWnd::RegisterWindowClass()
{
    WNDCLASS wc = { 0 };
    wc.style = GetClassStyle();
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIcon = NULL;
    wc.lpfnWndProc = CWindowWnd::__WndProc;

__WndProc是CWindowWnd的一个静态成员,这个函数值得看一下:

LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd* pThis = NULL;
    if( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    } 
    else {
        pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
            if( pThis->m_bSubclassed ) pThis->Unsubclass();
            pThis->m_hWnd = NULL;
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }
    if( pThis != NULL ) {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    else {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

针对WM_NCCREATE这个消息有一个管用技巧,先复习下这个消息:

The WM_NCCREATE message is sent prior to the WM_CREATE message when a window is first created.

我的理解中,这个消息应该是窗口收到的第一个消息。

还有WM_NCDESTROY这个特殊的消息。

当然了,还有这个牛逼的戏法:

::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));

总的来说一句话,两个消息NC create destroy对应的应该有连个函数,但是原本的OnNcCreate响应隐藏在了__WndProc中,还有一个函数OnFinalMessage。this指针藏在SetWindowLongPtr(hWnd, GWLP_USERDATA,,,

好了底层需要注意的就只有这两个函数,其他的消息都应该是抛给子类去处理了。

既然是玩directUi,就重点关注一下WM_NCPAINT消息,也一个也很重要的消息WM_NCHITTEST。

不知道为什么这里用的都是NC系列消息。

NC应该是理解成none client,初步观察Duilib的size拖拉支持是使用NCHITTEST+SIZE消息来实现的。

看NCPAINT消息体里边没有任何代码这很诡异,所以还是看看完整的消息响应函数,是不是漏掉了什么:

    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        LRESULT lRes = 0;
        BOOL bHandled = TRUE;
        switch( uMsg ) {
        case WM_CREATE:        lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
        case WM_CLOSE:         lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
        case WM_DESTROY:       lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
        case WM_NCACTIVATE:    lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
        case WM_NCCALCSIZE:    lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
        case WM_NCPAINT:       lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
        case WM_NCHITTEST:     lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
        case WM_SIZE:          lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
        case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
        case WM_SYSCOMMAND:    lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
        default:
            bHandled = FALSE;
        }
        if( bHandled ) return lRes;
        if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
        return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

乍看之下这里的消息处理至少分为三层,CWindowWnd派生类本身没有处理的消息将会被送到m_pm中去处理,如果m_pm.MessageHandler返回false消息最后还是CWindowWnd处理。

bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
{
//#ifdef _DEBUG
//    switch( uMsg ) {
//    case WM_NCPAINT:
//    case WM_NCHITTEST:
//    case WM_SETCURSOR:
//       break;
//    default:
//       DUITRACE(_T("MSG: %-20s (%08ld)"), DUITRACEMSG(uMsg), ::GetTickCount());
//    }
//#endif
    // Not ready yet?
    if( m_hWndPaint == NULL ) return false;
    
    TNotifyUI* pMsg = NULL;
    while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) ) {
        m_aAsyncNotify.Remove(0);
        if( pMsg->pSender != NULL ) {
            if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
        }
        for( int j = 0; j < m_aNotifiers.GetSize(); j++ ) {
            static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
        }
        delete pMsg;
    }
    
    // Cycle through listeners
    for( int i = 0; i < m_aMessageFilters.GetSize(); i++ ) 
    {
        bool bHandled = false;
        LRESULT lResult = static_cast<IMessageFilterUI*>(m_aMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
        if( bHandled ) {
            lRes = lResult;
            return true;
        }
    }
    // Custom handling of events
    switch( uMsg ) {
    case WM_APP + 1:
        {
            for( int i = 0; i < m_aDelayedCleanup.GetSize(); i++ ) 
                delete static_cast<CControlUI*>(m_aDelayedCleanup[i]);
            m_aDelayedCleanup.Empty();
        }
        break;
    case WM_CLOSE:
        {
            // Make sure all matching "closing" events are sent
            TEventUI event = { 0 };
            event.ptMouse = m_ptLastMousePos;
            event.dwTimestamp = ::GetTickCount();
            if( m_pEventHover != NULL ) {
                event.Type = UIEVENT_MOUSELEAVE;
                event.pSender = m_pEventHover;
                m_pEventHover->Event(event);
            }
            if( m_pEventClick != NULL ) {
                event.Type = UIEVENT_BUTTONUP;
                event.pSender = m_pEventClick;
                m_pEventClick->Event(event);
            }

            SetFocus(NULL);

            // Hmmph, the usual Windows tricks to avoid
            // focus loss...
            HWND hwndParent = GetWindowOwner(m_hWndPaint);
            if( hwndParent != NULL ) ::SetFocus(hwndParent);
        }
        break;
    case WM_ERASEBKGND:
        {
            // We'll do the painting here...
            lRes = 1;
        }
        return true;
    case WM_PAINT:
        {
            // Should we paint?
            RECT rcPaint = { 0 };
            if( !::GetUpdateRect(m_hWndPaint, &rcPaint, FALSE) ) return true;
            if( m_pRoot == NULL ) {
                PAINTSTRUCT ps = { 0 };
                ::BeginPaint(m_hWndPaint, &ps);
                ::EndPaint(m_hWndPaint, &ps);
                return true;
            }            
            // Do we need to resize anything?
            // This is the time where we layout the controls on the form.
            // We delay this even from the WM_SIZE messages since resizing can be
            // a very expensize operation.
            if( m_bUpdateNeeded ) {
                m_bUpdateNeeded = false;
                RECT rcClient = { 0 };
                ::GetClientRect(m_hWndPaint, &rcClient);
                if( !::IsRectEmpty(&rcClient) ) {
                    if( m_pRoot->IsUpdateNeeded() ) {
                        m_pRoot->SetPos(rcClient);
                        if( m_hDcOffscreen != NULL ) ::DeleteDC(m_hDcOffscreen);
                        if( m_hDcBackground != NULL ) ::DeleteDC(m_hDcBackground);
                        if( m_hbmpOffscreen != NULL ) ::DeleteObject(m_hbmpOffscreen);
                        if( m_hbmpBackground != NULL ) ::DeleteObject(m_hbmpBackground);
                        m_hDcOffscreen = NULL;
                        m_hDcBackground = NULL;
                        m_hbmpOffscreen = NULL;
                        m_hbmpBackground = NULL;
                    }
                    else {
                        CControlUI* pControl = NULL;
                        while( pControl = m_pRoot->FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST) ) {
                            pControl->SetPos( pControl->GetPos() );
                        }
                    }
                    // We'll want to notify the window when it is first initialized
                    // with the correct layout. The window form would take the time
                    // to submit swipes/animations.
                    if( m_bFirstLayout ) {
                        m_bFirstLayout = false;
                        SendNotify(m_pRoot, DUI_MSGTYPE_WINDOWINIT,  0, 0, false);
                    }
                }
            }
            // Set focus to first control?
            if( m_bFocusNeeded ) {
                SetNextTabControl();
            }
            //
            // Render screen
            //
            // Prepare offscreen bitmap?
            if( m_bOffscreenPaint && m_hbmpOffscreen == NULL )
            {
                RECT rcClient = { 0 };
                ::GetClientRect(m_hWndPaint, &rcClient);
                m_hDcOffscreen = ::CreateCompatibleDC(m_hDcPaint);
                m_hbmpOffscreen = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                ASSERT(m_hDcOffscreen);
                ASSERT(m_hbmpOffscreen);
            }
            // Begin Windows paint
            PAINTSTRUCT ps = { 0 };
            ::BeginPaint(m_hWndPaint, &ps);
            if( m_bOffscreenPaint )
            {
                HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(m_hDcOffscreen, m_hbmpOffscreen);
                int iSaveDC = ::SaveDC(m_hDcOffscreen);
                if( m_bAlphaBackground ) {
                    if( m_hbmpBackground == NULL ) {
                        RECT rcClient = { 0 };
                        ::GetClientRect(m_hWndPaint, &rcClient);
                        m_hDcBackground = ::CreateCompatibleDC(m_hDcPaint);;
                        m_hbmpBackground = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                        ASSERT(m_hDcBackground);
                        ASSERT(m_hbmpBackground);
                        ::SelectObject(m_hDcBackground, m_hbmpBackground);
                        ::BitBlt(m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                            ps.rcPaint.bottom - ps.rcPaint.top, ps.hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                    }
                    else
                        ::SelectObject(m_hDcBackground, m_hbmpBackground);
                    ::BitBlt(m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                        ps.rcPaint.bottom - ps.rcPaint.top, m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                }
                m_pRoot->DoPaint(m_hDcOffscreen, ps.rcPaint);
                for( int i = 0; i < m_aPostPaintControls.GetSize(); i++ ) {
                    CControlUI* pPostPaintControl = static_cast<CControlUI*>(m_aPostPaintControls[i]);
                    pPostPaintControl->DoPostPaint(m_hDcOffscreen, ps.rcPaint);
                }
                ::RestoreDC(m_hDcOffscreen, iSaveDC);
                ::BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                    ps.rcPaint.bottom - ps.rcPaint.top, m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                ::SelectObject(m_hDcOffscreen, hOldBitmap);

                if( m_bShowUpdateRect ) {
                    HPEN hOldPen = (HPEN)::SelectObject(ps.hdc, m_hUpdateRectPen);
                    ::SelectObject(ps.hdc, ::GetStockObject(HOLLOW_BRUSH));
                    ::Rectangle(ps.hdc, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
                    ::SelectObject(ps.hdc, hOldPen);
                }
            }
            else
            {
                // A standard paint job
                int iSaveDC = ::SaveDC(ps.hdc);
                m_pRoot->DoPaint(ps.hdc, ps.rcPaint);
                ::RestoreDC(ps.hdc, iSaveDC);
            }
            // All Done!
            ::EndPaint(m_hWndPaint, &ps);
        }
        // If any of the painting requested a resize again, we'll need
        // to invalidate the entire window once more.
        if( m_bUpdateNeeded ) {
            ::InvalidateRect(m_hWndPaint, NULL, FALSE);
        }
        return true;
    case WM_PRINTCLIENT:
        {
            RECT rcClient;
            ::GetClientRect(m_hWndPaint, &rcClient);
            HDC hDC = (HDC) wParam;
            int save = ::SaveDC(hDC);
            m_pRoot->DoPaint(hDC, rcClient);
            // Check for traversing children. The crux is that WM_PRINT will assume
            // that the DC is positioned at frame coordinates and will paint the child
            // control at the wrong position. We'll simulate the entire thing instead.
            if( (lParam & PRF_CHILDREN) != 0 ) {
                HWND hWndChild = ::GetWindow(m_hWndPaint, GW_CHILD);
                while( hWndChild != NULL ) {
                    RECT rcPos = { 0 };
                    ::GetWindowRect(hWndChild, &rcPos);
                    ::MapWindowPoints(HWND_DESKTOP, m_hWndPaint, reinterpret_cast<LPPOINT>(&rcPos), 2);
                    ::SetWindowOrgEx(hDC, -rcPos.left, -rcPos.top, NULL);
                    // NOTE: We use WM_PRINT here rather than the expected WM_PRINTCLIENT
                    //       since the latter will not print the nonclient correctly for
                    //       EDIT controls.
                    ::SendMessage(hWndChild, WM_PRINT, wParam, lParam | PRF_NONCLIENT);
                    hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
                }
            }
            ::RestoreDC(hDC, save);
        }
        break;
    case WM_GETMINMAXINFO:
        {
            LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
            if( m_szMinWindow.cx > 0 ) lpMMI->ptMinTrackSize.x = m_szMinWindow.cx;
            if( m_szMinWindow.cy > 0 ) lpMMI->ptMinTrackSize.y = m_szMinWindow.cy;
            if( m_szMaxWindow.cx > 0 ) lpMMI->ptMaxTrackSize.x = m_szMaxWindow.cx;
            if( m_szMaxWindow.cy > 0 ) lpMMI->ptMaxTrackSize.y = m_szMaxWindow.cy;
        }
        break;
    case WM_SIZE:
        {
            if( m_pFocus != NULL ) {
                TEventUI event = { 0 };
                event.Type = UIEVENT_WINDOWSIZE;
                event.pSender = m_pFocus;
                event.dwTimestamp = ::GetTickCount();
                m_pFocus->Event(event);
            }
            if( m_pRoot != NULL ) m_pRoot->NeedUpdate();
        }
        return true;
    case WM_TIMER:
        {
            for( int i = 0; i < m_aTimers.GetSize(); i++ ) {
                const TIMERINFO* pTimer = static_cast<TIMERINFO*>(m_aTimers[i]);
                if( pTimer->hWnd == m_hWndPaint && pTimer->uWinTimer == LOWORD(wParam) && pTimer->bKilled == false) {
                    TEventUI event = { 0 };
                    event.Type = UIEVENT_TIMER;
                    event.pSender = pTimer->pSender;
                    event.wParam = pTimer->nLocalID;
                    event.dwTimestamp = ::GetTickCount();
                    pTimer->pSender->Event(event);
                    break;
                }
            }
        }
        break;
    case WM_MOUSEHOVER:
        {
            m_bMouseTracking = false;
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            CControlUI* pHover = FindControl(pt);
            if( pHover == NULL ) break;
            // Generate mouse hover event
            if( m_pEventHover != NULL ) {
                TEventUI event = { 0 };
                event.ptMouse = pt;
                event.Type = UIEVENT_MOUSEHOVER;
                event.pSender = m_pEventHover;
                event.dwTimestamp = ::GetTickCount();
                m_pEventHover->Event(event);
            }
            // Create tooltip information
            CDuiString sToolTip = pHover->GetToolTip();
            if( sToolTip.IsEmpty() ) return true;
            ::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));
            m_ToolTip.cbSize = sizeof(TOOLINFO);
            m_ToolTip.uFlags = TTF_IDISHWND;
            m_ToolTip.hwnd = m_hWndPaint;
            m_ToolTip.uId = (UINT_PTR) m_hWndPaint;
            m_ToolTip.hinst = m_hInstance;
            m_ToolTip.lpszText = const_cast<LPTSTR>( (LPCTSTR) sToolTip );
            m_ToolTip.rect = pHover->GetPos();
            if( m_hwndTooltip == NULL ) {
                m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWndPaint, NULL, m_hInstance, NULL);
                ::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);
            }
            ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &m_ToolTip);
            ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);
        }
        return true;
    case WM_MOUSELEAVE:
        {
            if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);
            if( m_bMouseTracking ) ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) -1);
            m_bMouseTracking = false;
        }
        break;
    case WM_MOUSEMOVE:
        {
            // Start tracking this entire window again...
            if( !m_bMouseTracking ) {
                TRACKMOUSEEVENT tme = { 0 };
                tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER | TME_LEAVE;
                tme.hwndTrack = m_hWndPaint;
                tme.dwHoverTime = m_hwndTooltip == NULL ? 400UL : (DWORD) ::SendMessage(m_hwndTooltip, TTM_GETDELAYTIME, TTDT_INITIAL, 0L);
                _TrackMouseEvent(&tme);
                m_bMouseTracking = true;
            }
            // Generate the appropriate mouse messages
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pNewHover = FindControl(pt);
            if( pNewHover != NULL && pNewHover->GetManager() != this ) break;
            TEventUI event = { 0 };
            event.ptMouse = pt;
            event.dwTimestamp = ::GetTickCount();
            if( pNewHover != m_pEventHover && m_pEventHover != NULL ) {
                event.Type = UIEVENT_MOUSELEAVE;
                event.pSender = m_pEventHover;
                m_pEventHover->Event(event);
                m_pEventHover = NULL;
                if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);
            }
            if( pNewHover != m_pEventHover && pNewHover != NULL ) {
                event.Type = UIEVENT_MOUSEENTER;
                event.pSender = pNewHover;
                pNewHover->Event(event);
                m_pEventHover = pNewHover;
            }
            if( m_pEventClick != NULL ) {
                event.Type = UIEVENT_MOUSEMOVE;
                event.pSender = m_pEventClick;
                m_pEventClick->Event(event);
            }
            else if( pNewHover != NULL ) {
                event.Type = UIEVENT_MOUSEMOVE;
                event.pSender = pNewHover;
                pNewHover->Event(event);
            }
        }
        break;
    case WM_LBUTTONDOWN:
        {
            // We alway set focus back to our app (this helps
            // when Win32 child windows are placed on the dialog
            // and we need to remove them on focus change).
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            if( pControl == NULL ) break;
            if( pControl->GetManager() != this ) break;
            m_pEventClick = pControl;
            pControl->SetFocus();
            SetCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONDOWN;
            event.pSender = pControl;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            pControl->Event(event);
        }
        break;
    case WM_LBUTTONDBLCLK:
        {
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            if( pControl == NULL ) break;
            if( pControl->GetManager() != this ) break;
            SetCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_DBLCLICK;
            event.pSender = pControl;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            pControl->Event(event);
            m_pEventClick = pControl;
        }
        break;
    case WM_LBUTTONUP:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            if( m_pEventClick == NULL ) break;
            ReleaseCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONUP;
            event.pSender = m_pEventClick;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            m_pEventClick->Event(event);
            m_pEventClick = NULL;
        }
        break;
    case WM_RBUTTONDOWN:
        {
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            if( pControl == NULL ) break;
            if( pControl->GetManager() != this ) break;
            pControl->SetFocus();
            SetCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_RBUTTONDOWN;
            event.pSender = pControl;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            pControl->Event(event);
            m_pEventClick = pControl;
        }
        break;
    case WM_CONTEXTMENU:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ::ScreenToClient(m_hWndPaint, &pt);
            m_ptLastMousePos = pt;
            if( m_pEventClick == NULL ) break;
            ReleaseCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_CONTEXTMENU;
            event.pSender = m_pEventClick;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.lParam = (LPARAM)m_pEventClick;
            event.dwTimestamp = ::GetTickCount();
            m_pEventClick->Event(event);
            m_pEventClick = NULL;
        }
        break;
    case WM_MOUSEWHEEL:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ::ScreenToClient(m_hWndPaint, &pt);
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            if( pControl == NULL ) break;
            if( pControl->GetManager() != this ) break;
            int zDelta = (int) (short) HIWORD(wParam);
            TEventUI event = { 0 };
            event.Type = UIEVENT_SCROLLWHEEL;
            event.pSender = pControl;
            event.wParam = MAKELPARAM(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0);
            event.lParam = lParam;
            event.wKeyState = MapKeyState();
            event.dwTimestamp = ::GetTickCount();
            pControl->Event(event);

            // Let's make sure that the scroll item below the cursor is the same as before...
            ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) MAKELPARAM(m_ptLastMousePos.x, m_ptLastMousePos.y));
        }
        break;
    case WM_CHAR:
        {
            if( m_pFocus == NULL ) break;
            TEventUI event = { 0 };
            event.Type = UIEVENT_CHAR;
            event.chKey = (TCHAR)wParam;
            event.ptMouse = m_ptLastMousePos;
            event.wKeyState = MapKeyState();
            event.dwTimestamp = ::GetTickCount();
            m_pFocus->Event(event);
        }
        break;
    case WM_KEYDOWN:
        {
            if( m_pFocus == NULL ) break;
            TEventUI event = { 0 };
            event.Type = UIEVENT_KEYDOWN;
            event.chKey = (TCHAR)wParam;
            event.ptMouse = m_ptLastMousePos;
            event.wKeyState = MapKeyState();
            event.dwTimestamp = ::GetTickCount();
            m_pFocus->Event(event);
            m_pEventKey = m_pFocus;
        }
        break;
    case WM_KEYUP:
        {
            if( m_pEventKey == NULL ) break;
            TEventUI event = { 0 };
            event.Type = UIEVENT_KEYUP;
            event.chKey = (TCHAR)wParam;
            event.ptMouse = m_ptLastMousePos;
            event.wKeyState = MapKeyState();
            event.dwTimestamp = ::GetTickCount();
            m_pEventKey->Event(event);
            m_pEventKey = NULL;
        }
        break;
    case WM_SETCURSOR:
        {
            if( LOWORD(lParam) != HTCLIENT ) break;
            if( m_bMouseCapture ) return true;

            POINT pt = { 0 };
            ::GetCursorPos(&pt);
            ::ScreenToClient(m_hWndPaint, &pt);
            CControlUI* pControl = FindControl(pt);
            if( pControl == NULL ) break;
            if( (pControl->GetControlFlags() & UIFLAG_SETCURSOR) == 0 ) break;
            TEventUI event = { 0 };
            event.Type = UIEVENT_SETCURSOR;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = MapKeyState();
            event.dwTimestamp = ::GetTickCount();
            pControl->Event(event);
        }
        return true;
    case WM_NOTIFY:
        {
            LPNMHDR lpNMHDR = (LPNMHDR) lParam;
            if( lpNMHDR != NULL ) lRes = ::SendMessage(lpNMHDR->hwndFrom, OCM__BASE + uMsg, wParam, lParam);
            return true;
        }
        break;
    case WM_COMMAND:
        {
            if( lParam == 0 ) break;
            HWND hWndChild = (HWND) lParam;
            lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
            return true;
        }
        break;
    case WM_CTLCOLOREDIT:
    case WM_CTLCOLORSTATIC:
        {
            // Refer To: http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx
            // Read-only or disabled edit controls do not send the WM_CTLCOLOREDIT message; instead, they send the WM_CTLCOLORSTATIC message.
            if( lParam == 0 ) break;
            HWND hWndChild = (HWND) lParam;
            lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
            return true;
        }
        break;
    default:
        break;
    }

    pMsg = NULL;
    while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) ) {
        m_aAsyncNotify.Remove(0);
        if( pMsg->pSender != NULL ) {
            if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
        }
        for( int j = 0; j < m_aNotifiers.GetSize(); j++ ) {
            static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
        }
        delete pMsg;
    }

    return false;
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

我去这里代码有点多,先简单捋一下,首先处理了如下消息:

WM_CTLCOLOREDIT:
WM_CTLCOLORSTATIC
WM_COMMAND:
WM_NOTIFY:
WM_SETCURSOR:
WM_KEYUP
WM_KEYDOWN
WM_CHAR
WM_MOUSEWHEEL
WM_CONTEXTMENU
WM_RBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONDOWN
WM_MOUSEMOVE
WM_MOUSELEAVE
WM_MOUSEHOVER
WM_TIMER
WM_SIZE
WM_GETMINMAXINFO
WM_PRINTCLIENT
WM_PAINT
WM_ERASEBKGND
WM_CLOSE
WM_APP

除了这些消息还有一个特别的东西需要留意:

m_aAsyncNotify以后再分析

 

 

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

posted @ 2013-03-07 21:39 Enic 阅读(2210) | 评论 (0)编辑 收藏

质量最大vczh粉(402740419) 10:13:17

nobody(1575393351)  10:10:09
无锁队列,怎么可能

质量最大vczh粉(402740419) 10:13:23

用link做,轻轻松松

nobody(1575393351) 10:13:40

多个线程同时从队列里面取,怎么可能不加锁。。

uczh.0xDEADBEEF(365128087) 10:13:44

他已经发请求了

vczh四号粉丝(342775210) 10:13:51

可以不加锁

质量最大vczh粉(402740419) 10:13:51

用link做,真心不用加锁

vczh四号粉丝(342775210) 10:13:55

不过必须用cas

质量最大vczh粉(402740419) 10:14:03

CAS是啥

vczh四号粉丝(342775210) 10:14:06

否则做不了多线程的并发

nobody(1575393351) 10:14:13

link是什么东西

质量最大vczh粉(402740419) 10:30:26

陈梓瀚<vczh@163.com>  10:27:16
用interlocked compare exchange
当tail == null就换一个new link进去
这样偏麻烦

vczh四号粉丝(342775210) 10:30:28

会把问题复杂化

质量最大vczh粉(402740419) 10:30:29

有简单的办法

uczh.0xDEADBEEF(365128087) 10:30:30

但性能很好的

质量最大vczh粉(402740419) 10:30:43

类似ngxqueue的办法,保证链表里始终有一个结点

质量最大vczh粉(402740419) 10:30:49

这样可以避免很多麻烦

uczh.0xDEADBEEF(365128087) 10:31:03

质量最大vczh粉(402740419) 10:31:07

只有构造和析构的时候 多线程访问会出问题,但这时候一般又不会多线程访问

vczh.Iskandar<vczh@163.com> 10:31:17

就算如此你也要对tail->next == null的时候做判断嘛

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:31:22

质量最大vczh粉(402740419)  10:31:07
只有构造和析构的时候 多线程访问会出问题,但这时候一般又不会多线程访问
不要做任何假设

vczh.Iskandar<vczh@163.com> 10:31:26

这样才能避免两个线程同时push

质量最大vczh粉(402740419) 10:31:48

VCZH.粉丝数组[0](85126585)  10:31:22
质量最大vczh粉(402740419)  10:31:07
只有构造和析构的时候 多线程访问会出问题,但这时候一般又不会多线程访问
不要做任何假设
不是假设,构造还没完成的时候就把对象传给多个线程从设计上来说就是有毛病的

质量最大vczh粉(402740419) 10:31:59

析构也类似

质量最大vczh粉(402740419) 10:32:14

性质上和你在别的线程进行了野指针操作没有区别

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:32:21

ooseven(147340642) 10:32:31

这样设计的话,对象的生命周期很难控制

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:32:58

reference counting嘛

质量最大vczh粉(402740419) 10:33:00

肯定是构造完了,才丢给shared_ptr或者别的什么东西,然后才会多线程考虑持有这个对象

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:33:02

现在流行

vczh.Iskandar<vczh@163.com> 10:33:08

析构的时候

vczh.Iskandar<vczh@163.com> 10:33:13

肯定是所有shared_ptr都完蛋了

vczh.Iskandar<vczh@163.com> 10:33:17

所以这个时候也不会有人访问了

质量最大vczh粉(402740419) 10:33:36

陈梓瀚<vczh@163.com>  10:31:17
就算如此你也要对tail->next == null的时候做判断嘛
嗯嗯,compareandswap就是这里啊

vczh四号粉丝(342775210) 10:34:23

不仅仅是null的判断吧

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:34:33

循环队列里边

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:34:44

tail->next == head

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:34:50

貌似这样的

质量最大vczh粉(402740419) 10:34:56

循环队列?

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:35:04

ring

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:35:06

buffer

质量最大vczh粉(402740419) 10:35:15

ringbuffer是另一个概念= =

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:35:24

囧,我错了

质量最大vczh粉(402740419) 10:35:41

刚才那个是最简单的,每个节点只能存一个pointer或者其它相同大小的东西

vczh四号粉丝(342775210) 10:35:43

http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html

质量最大vczh粉(402740419) 10:37:16

= = 堆栈这么做是找死啊

质量最大vczh粉(402740419) 10:37:19

就是算法有问题

vczh.Iskandar<vczh@163.com> 10:37:50

我觉得这个例子有问题

vczh.Iskandar<vczh@163.com> 10:37:55

你每一次push新数据进去的时候

vczh四号粉丝(342775210) 10:37:57

你的系统先把10Wtps过了,再说并发

vczh.Iskandar<vczh@163.com> 10:38:04

都不能重用节点

vczh.Iskandar<vczh@163.com> 10:38:06

都必须new一个新的

质量最大vczh粉(402740419) 10:38:45

vczh四号粉丝(342775210)  10:37:57
你的系统先把10Wtps过了,再说并发
噗,我的服务端是单进程多线程模型

质量最大vczh粉(402740419) 10:38:53

客户端才在搞多线程

质量最大vczh粉(402740419) 10:39:04

说错了

质量最大vczh粉(402740419) 10:39:08

服务端是单线程多金正

质量最大vczh粉(402740419) 10:41:02

我的引擎里当初做一个类似tbb那种task式的并行框架(或者类似boost.asio)

质量最大vczh粉(402740419) 10:41:20

因为赶着出工,直接拿一个lockfree的list就上了

小老鼠(273245994) 10:41:25

沈阳发生爆炸了

质量最大vczh粉(402740419) 10:41:38

结果性能还可以

vczh.Iskandar<vczh@163.com> 10:41:43

什么爆炸

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:42:35

因为赶着出工,直接拿一个lockfree的list就上了
自己写的?

质量最大vczh粉(402740419) 10:42:51

很久很久很久以前写的

质量最大vczh粉(402740419) 10:43:05

然后写这个的时候不知道mem barrier

质量最大vczh粉(402740419) 10:43:11

加到引擎里的时候 加了下barrier

小老鼠(273245994) 10:43:21

9时,太原街地下通道

质量最大vczh粉(402740419) 10:43:34

当时还问了这两位将近一天……

小老鼠(273245994) 10:43:46

附近1公里都有震感

小老鼠(273245994) 10:43:57

你说这次会不会还是死35人.

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:44:27

牛逼

装配脑袋(2380479792) 10:44:37

两·会就不让他们好好开

 

小老鼠(273245994) 10:43:57

你说这次会不会还是死35人.

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:44:27

牛逼

装配脑袋(2380479792) 10:44:37

两·会就不让他们好好开

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:44:40

我遇到这个第一想法是开源的弄一个来

御虚舟北(314969051) 10:44:41

又黑人

质量最大vczh粉(402740419) 10:45:32

VCZH.粉丝数组[0](85126585)  10:44:40
我遇到这个第一想法是开源的弄一个来
假设需要一套整块功能,肯定用开源的

质量最大vczh粉(402740419) 10:45:46

如果只需求一个点…… 对我们搞移动的来说,port成本太高了……

质量最大vczh粉(402740419) 10:46:00

不过本质上来说这个还是几乎算是用开源的

质量最大vczh粉(402740419) 10:46:03

只是我人肉翻译了下而已

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:46:35

所以昨天被问到这个问题,我很反感那个家伙,,,

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:46:44

尼玛问这就是问我看过类似的帖子没,,,

质量最大vczh粉(402740419) 10:47:16

帖子?

vczh一千号粉丝(327385942) 10:47:29

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:47:41

就是说我看过讨论类似的论文没有

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:47:47

看过就能说两句

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:47:58

没看过,面试那一点时间能想出来

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:48:01

还见鬼了

质量最大vczh粉(402740419) 10:48:17

??

质量最大vczh粉(402740419) 10:48:24

我曾经面试一个 刚毕业的小伙子,也谈不上多优秀

质量最大vczh粉(402740419) 10:48:32

我面试就问的lock-free的队列

御虚舟北(314969051) 10:48:33

刚毕业的小伙子

质量最大vczh粉(402740419) 10:48:38

还不是linked-list

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:48:44

自己想出来了?

质量最大vczh粉(402740419) 10:48:44

是deque的

质量最大vczh粉(402740419) 10:49:03

自己肯定想不出来,但已经摸到边了啊,我稍微诱导了一下

质量最大vczh粉(402740419) 10:49:05

就出来了

vczh.Isotope(75497789) 10:49:27

菊苣们,这里能问算法题不?

质量最大vczh粉(402740419) 10:49:38

知道基本概念了这就是很直观的东西,需要上升到论文层面么……

质量最大vczh粉(402740419) 10:49:45

复杂一点的数据结构可能需要

质量最大vczh粉(402740419) 10:49:48

至少队列不需要啊= =

质量最大vczh粉(402740419) 10:50:18

啥算法题?工作需要还是自己瞎折腾

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:50:25

你考虑这些和我的方式不太一样,我觉得这个东西了解就行了,自己做是下下策
我是不是得改改了?

vczh.Isotope(75497789) 10:50:44

用1*2的矩形去覆盖m*n的矩形(m*n是偶数),问一共有多少种方法

质量最大vczh粉(402740419) 10:50:52

VCZH.粉丝数组[0](85126585)  10:50:26
你考虑这些和我的方式不太一样,我觉得这个东西了解就行了,自己做是下下策
做事的方式 和考察、自我考察的方式是两码事

质量最大vczh粉(402740419) 10:51:31

不然vczh大牛也不会做编译器和GUI了,反正也没人用

vczh.Iskandar<vczh@163.com> 10:51:51

小老鼠(273245994) 10:52:15

内伤了

质量最大vczh粉(402740419) 10:52:38

vczh.Isotope(75497789)  10:50:44
用1*2的矩形去覆盖m*n的矩形(m*n是偶数),问一共有多少种方法
ACM题?滚边去。我会,就是不告诉你

质量最大vczh粉(402740419) 10:52:40

ACM毒害人

vczh.Iskandar<vczh@163.com> 10:52:54

做ACM踢掉(逃

质量最大vczh粉(402740419) 10:53:02

vczh.Isotope(75497789) 10:53:05

不是ACM题

vczh的脑残粉(195719555) 10:53:08

vczh.Ismeow(65200296) 10:53:10

为什么踢掉……

vczh.Iskandar<vczh@163.com> 10:53:14

这些就是

vczh.Isotope(75497789) 10:53:17

好像是MS面试题

vczh.Iskandar<vczh@163.com> 10:53:21

这个群使用来讨论奇技淫巧的

vczh.Iskandar<vczh@163.com> 10:53:27

这是google的面试题,M$才不面这个

vczh.Konobuta(450635425) 10:53:48

看了下 

vczh.Konobuta(450635425) 10:54:05

用了原子指令 

质量最大vczh粉(402740419) 10:54:07

这是百度的面试题,google才不面这个

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:54:08

质量最大vczh粉(402740419)  10:50:52
VCZH.粉丝数组[0](85126585)  10:50:26
你考虑这些和我的方式不太一样,我觉得这个东西了解就行了,自己做是下下策
做事的方式 和考察、自我考察的方式是两码事
不然vczh大牛也不会做编译器和GUI了,反正也没人用
受教了,挤时间还是多把这些东西实现一下

vczh一千号粉丝(327385942) 10:54:50

vczh一千号粉丝(327385942) 10:55:12

做acm题还是不错的

Sean(123983971) 10:55:15

小矩形可以重叠吗?

vczh.Konobuta(450635425) 10:55:16

实际上还是相当于加锁,只是粒度更小 

vczh.Konobuta(450635425) 10:55:32

就怕有的平台不支持 

vczh.Iskandar<vczh@163.com> 10:55:42

不支持CAS的平台

vczh.Iskandar<vczh@163.com> 10:55:52

等你学会编程之后

vczh.Iskandar<vczh@163.com> 10:56:02

早就消失了

vczh.Konobuta(450635425) 10:54:05

用了原子指令 

质量最大vczh粉(402740419) 10:54:07

这是百度的面试题,google才不面这个

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:54:08

质量最大vczh粉(402740419)  10:50:52
VCZH.粉丝数组[0](85126585)  10:50:26
你考虑这些和我的方式不太一样,我觉得这个东西了解就行了,自己做是下下策
做事的方式 和考察、自我考察的方式是两码事
不然vczh大牛也不会做编译器和GUI了,反正也没人用
受教了,挤时间还是多把这些东西实现一下

vczh一千号粉丝(327385942) 10:54:50

vczh一千号粉丝(327385942) 10:55:12

做acm题还是不错的

Sean(123983971) 10:55:15

小矩形可以重叠吗?

vczh.Konobuta(450635425) 10:55:16

实际上还是相当于加锁,只是粒度更小 

vczh.Konobuta(450635425) 10:55:32

就怕有的平台不支持 

vczh.Iskandar<vczh@163.com> 10:55:42

不支持CAS的平台

vczh.Iskandar<vczh@163.com> 10:55:52

等你学会编程之后

vczh.Iskandar<vczh@163.com> 10:56:02

早就消失了

vczh.Konobuta(450635425) 10:56:40

万一有呢? 

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:56:43

vczh.Iskandar<vczh@163.com>  10:55:42
不支持CAS的平台
等你学会编程之后
早就消失了
确实,我没见过,除了学校C51单片机

装配脑袋(2380479792) 10:56:50

连ARM都支持

vczh.Iskandar<vczh@163.com> 10:56:50

就是没有

装配脑袋(2380479792) 10:57:02

不支持没法办事

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:57:05

如果有,那么肯定是中断来做时分的

vczh.Ismeow(65200296) 10:57:04

51这种平台你会做什么抢占式Multiprogramming么……

装配脑袋(2380479792) 10:57:07

显卡都支持。。

vczh.Ismeow(65200296) 10:57:10

我相信不会吧

vczh.Konobuta(450635425) 10:57:24

好吧 

vczh.Konobuta(450635425) 10:57:39

我也换成这个 

vczh.Iskandar<vczh@163.com> 10:57:59

再说了,如果不用CAS,你是没有任何办法的

质量最大vczh粉(402740419) 10:58:25

不支持CAS的设备一般就是单核设备了吧

vczh.脑残粉(50923132) 10:58:27

没有CAS,同步只能

质量最大vczh粉(402740419) 10:58:42

单核设备 还是能保证单条指令原子性的吧

vczh.Ismeow(65200296) 10:58:52

不支持CAS的设备一般是不支持多任务的设备……

质量最大vczh粉(402740419) 10:59:03

用中断做分时任务是OK的

vczh.Ismeow(65200296) 10:59:27

问题是就那点可怜的资源……

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:59:51

多核 多中断

VCZH.粉丝数组[0]<errorcpp@qq.com> 10:59:55

就sb了

vczh.Ismeow(65200296) 10:59:56

你做个什么调度就爆了

VCZH.粉丝数组[0]<errorcpp@qq.com> 11:00:17

不过这样SB的CPU估计没人用

从未来‏̶过‪(815330718) 11:00:33

没有cas, 硬生生的 用不可屏蔽中断+变量 造一个...

vczh.Ismeow(65200296) 11:00:41

从未来‏̶过‪(815330718) 11:00:42

(逃

vczh.Ismeow(65200296) 11:00:54

NMI弄一个,不过这么弄就要硬件支持吧

vczh.Konobuta(450635425) 11:01:08

uczh.0xDEADBEEF(365128087) 11:01:24

vczh.Iskandar<vczh@163.com> 11:02:10

连cas都没有的硬件

从未来‏̶过‪(815330718) 11:02:16

只会写代码,不如去种田
http://www.oschina.net/news/38229/teach-kids-to-farm-not-code

vczh.Iskandar<vczh@163.com> 11:02:18

你想做多线程的事情

小老鼠(273245994) 11:02:19

http://slide.news.sina.com.cn/c/slide_1_2841_30492.html#p=1

vczh.Iskandar<vczh@163.com> 11:02:21

只能踩死

质量最大vczh粉(402740419) 11:05:35

vczh

质量最大vczh粉(402740419) 11:05:43

我今年6月份开始,要大规模做UI类的东西

vczh.Iskandar<vczh@163.com> 11:05:53

你不是早就做了吗

质量最大vczh粉(402740419) 11:06:11

我什么时候大规模做过可商业化的UI…… 除了在百度

vczh.Konobuta(450635425) 11:06:21

vczh.Konobuta(450635425) 11:06:31

教我 

vczh.Iskandar<vczh@163.com> 11:06:41

不是萌妹纸,滚!

vczh.Konobuta(450635425) 11:06:47

入群求节操(152606004) 11:06:50


教我

vczh.脑残粉(50923132) 11:06:58

vczh.Iskandar<vczh@163.com>  11:06:41
不是萌妹纸,滚!

御虚舟北(314969051) 11:07:00

不是萌妹纸,滚!

质量最大vczh粉(402740419) 11:07:08

不是萌妹纸,滚!

vczh.Konobuta(450635425) 11:07:11

质量最大vczh粉(402740419) 11:07:12

话说回来

质量最大vczh粉(402740419) 11:07:22

GacUI到那时候能完善到满足我的需求么= =

质量最大vczh粉(402740419) 11:07:30

不然的话,我是用Qt呢还是Qt呢还是Qt呢?

 

 

 

暂时的理解:

队列如果限定插入只从head,弹出只从tail,那么只要满足head != tail就是,一读取一写就是安全的。


posted @ 2013-03-04 11:14 Enic 阅读(1478) | 评论 (0)编辑 收藏

1.building vc solution under console
"D:\Program Files\Microsoft Visual Studio 9.0
\Common7\IDE\devenv" /build debug /out "aa.log" xxx.sln
http://blog.csdn.net/sm_crystal/article/details/6993767

2.emacs show line numbers
M-x linum-mode (or global-linum-mode), and put (global-linum-mode t) in your ~/.emacs (or ~/.emacs.d/init.el) to enable it at startup.
linum: separating line numbers from text
find this pice of code in linum.el: (setq width (max with (length str)))
change to (setq width (max width (+ (length str) 1)))
conctol the line number format: (setq linum-format "%3d")
set on for appointed mode:
(setq linum-mode-inhibit-modes-list '(eshell-mode
                                      shell-mode
                                      erc-mode
                                      jabber-roster-mode
                                      jabber-chat-mode
                                      gnus-group-mode
                                      gnus-summary-mode
                                      gnus-article-mode))

(defadvice linum-on (around linum-on-inhibit-for-modes)
  "Stop the load of linum-mode for some major modes."
    (unless (member major-mode linum-mode-inhibit-modes-list)
      ad-do-it))

(ad-activate 'linum-on)
compile .el to .elc: atl+x byte-compile-file
http://www.emacswiki.org/emacs/LineNumbers

3.using gzip - compress/uncompress file
compress: gzip [file name]
uncompress: gunzip [file name]
keep the input file: gunzip [file.gz] -c >> [file]
gunzip/gzip -c which simply writes the output stream to stdout
compress all the files under a director: -r
http://blog.csdn.net/yuyongpeng/article/details/1818717

4.emacs do not auto save backup files
(setq auto-save-default nil)

5.emacs close file ctrl+x k

posted @ 2013-03-04 09:10 Enic 阅读(274) | 评论 (0)编辑 收藏

3.1调试测试

×我们必须创建测试以重现问题

×我们必须多次运行测试以简化问题

×我们必须重新运行测试以观察运行过程

×我们必须重新运行测试以验证修改是否成功

×每个版本发布之前,我们必须重新运行测试,以便发现将来不会再次出现,这种称为回归测试

在调试过程中需要频繁的进行自动测试,应此最好尽可能的采用自动化测试。通常通过使用自动化测试技术,可以更容易的进行全面测试,自动化测试的好处在于:

×可以重用已有测试

×可以进行一些困难的、无法手工执行的测试(如:大规模的随机性测试)

×重复测试

×增强对软件的信心

 

3.2控制程序

        通常,自动化测试必须模拟程序所处的环境---也就是说,测试必须提供程序的输入,并且评估程序的输出。但是模拟环境需要很多技巧,如果环境中包括和程序进行交互的用户,自动测试就必须模拟真实的用户(包括他们的所有能力)。

        通过区分不同的接口,可以避开部分模拟难题,从而使得控制和评估都更易于自动化。下图是典型的三层接口划分:

×表现层处理和用户(或者构建程序环境的任何事物)之间的交互

×功能层封装程序的实际功能,功能独立于表现层

×单元层把功能分解成多个单元,这些单元相互协作形成一个整体

image

 

 

3.3在表现层测试

3.3.1低级交互

        在最低级的抽象级别,用户输入被看做鼠标和键盘的事件流,这种事件流可以是被捕获和重放,即用时间记录器的时间流替代实际输入设备的事件流。

(PS:如果是在windows上测试需要UI交互的程序,貌似可以直接简单的试用key_event mouse_event等几个api就能模拟时间送进来了;当然,还有socket类的测试,管道什么的,,,)

image

3.3.2系统级交互(高阶主题,主要是将在系统(如虚拟机)级别模拟外部操作)

 

3.3.3高级交互

        使用更高级抽象级别的事件流(或者脚本)来模拟外部操作。比如图形程序的测试,以前是直接算坐标控制,现在用更聪明的手段(标识button的text,输入指定的语句而不是裸的**_event)。简而言之就是输入更加具有逻辑性,更加接近“人工智能”

image

 

3.3.4 评估测试结果

        不管是事件流还是通过用户控件控制应用程序,都存在一个重要的问题:模拟环境必须检查程序的输出。

×必须通过检查输出进行同步,应为模拟用户可能会一直等待直到一个特定的动作结束。

×必须通过检查程序输出来进行结果评估,测试的最终目的是确定结果是否和我们的预期相符。

        表现层测试的优点是:它总能实现。我们总是可以模拟和自动执行用户的行为。但是,这是唯一的优点。通常表现层测试只是用于:

×问题发生在表现层

×计算机程序可以很方便的调用表现层

×没有其他的选择(如:由于表现层和功能层没有被清晰的分离,或者无法在较低层次上进行测试)

界面对人越友好,它对计算机程序就越不友好。。。所以表现层测试应该不是最适合自动化测试的接口(至少对非表示层coder来说)

 

3.4在功能层测试

        相比较于模拟用户交互,更加可取的方法是为程序设计一个适合于进行自动化的接口---或者通俗的说,设计接口时要考虑和测试系统的交互。比如通过提供脚本语言接口,脚本语言允许最终用户或者测试人员通过简单的方式自动执行某些任务。

        在功能层进行测试的最大优点是:很容易获取和评估结果。但是,这种测试的前提条件是能清晰的分离表现层和功能层。而一些陈旧的程序都是独立的整体,没有进行表现层和功能层的分离。这种情况下,有三种选择:

×继续在表现层恶心的测试,然后继续纠结

×重新进行大幅度的重新设计,以分离表现层和功能层,或者至少减少他们之间的依赖关系

×分解程序,并且直接测试独立的单元

 

3.5在单元层测试

        任何复杂的程度都可以分解成大量独立的单元---子程序、函数、库、模块、抽象数据类型、对象、类、包、组建、beans或者设计方案和语言提供的任何分解机制。单元之间通过接口同学---就像程序之间通过他们所处的环境进行通信一样。

        现在的想法不是需要自动运行整个程序,而是自动运行某个特定的单元。其优点是自动运行分离的单元一般都比自动运行整个程序容易的多。当然,缺点是自能自动化某个特定的单元行为,于是必须考虑在分离单元的过程中引入的问题。

        最终用户通常是不能访问单元的,因此不可能通过用户脚本来执行系统的功能。但是,程序员可以使用外围程序访问服务的方式访问单元(PS: 这句有点绕口,感觉是让程序员自己去写code做单元测试)

        所有的单元测试工具都提供了一个能组织大量单独测试用例的测试框架---每个测试覆盖一个独立的单元。单元测试应该能在没有任何用户交互的情况下自动运行,测试框架会按照要求运行部分或者所有的单元测试,然后概要显示运行单元测试以及各自的输出结果。运行某一个单元测试时,测试框架会按照以下三个步骤进行:

×建立单元测试以及运行的周边环境。通常一个单元可能需要其他单元或者操作环境的服务。该步骤建立起能使测试运行的环境。

×执行单元测试。每个测试用例覆盖该单元的一个可能的行为,用例首先执行所有操作,然后验证输出是否与预期相符。

×重新清理测试环境。

 

3.6分离单元

        有一些程序的功能层依赖于表现层,根本不可能把他们分离。比如print_to_file,把当前网页打印到文件中。为了防止覆盖已经存在的文件,会请求用户确认是否已经存在。(这个其实也可以使用的代码搞定,麻烦点,不过“确认”这个功能的测试就是必须UI和用户参与)

image

×表现层依赖功能层,应为他需要调用print_to_file()

×功能层依赖表现层,应为他需要调用confirm_loss()

问题就来了:如何切断依赖关系,使单元可以更好分离?

对于这个例子处理起来比较容易。可以让函数按照两种方式运行:自动模式禁止用户确认功能,总是返回true;交互模式,打开用户确认功能,等待用户回答。更加通用的方式是:参数化print_to_file函数,使他能与不同的表现层工作。

image

(PS:其实还可以通过引入一个中间层来解决,假设给print_to_file()加上参数,然后core不再依赖pressntation,而是依赖一个消息模块、或者控制模块,那么只要写一个模拟发送消息、模拟控制的模块即可。解决循环依赖直接的办法是引入中间层)

 

3.7为调试而设计

        依赖抽象而不是具象这一原则对于减少依赖关系有很大帮助。实际上可以利用这种方法创建整个应用程序框架,其中最流行的一个例子就是模型-视图-控制器架构模式,该模式能从应用程序级上解除功能层和表现层之间的耦合。

image

 

        如何创建一个这样的系统?最关键的还是分离功能层和表现层。我们决不希望核心功能依赖某个特定视图。MVC模式就是解决这类问题的一个通用方案。他把职责分解为两个部分:

×模型管理核心数据,并且提供处理这些核心数据的服务。

×个总观察者注册或者粘附(attach)在模型上,核心数据一旦发生变化,他们就会得到通知。

观察者又可以分成两种类型:

×视图负责以特定的方式显示核心数据

×控制器负责处理输入时间并调用模型服务

用户和控制器交互是,他最终可能会调用一个改变核心数据的服务。这是注册在模型上的所有视图都会得到通知。也就是说,他们能从模型那里获得数据以及更新显示。从而用户也就得到反馈。

MVC给测试和调试带来的好处:对于测试来说可以创建和添加新的控制器来调用模型提供的服务---例如,能自动记录执行这些服务的控制器。对于调试来说,可以支持特殊的视图来记录模型的所有变化。最后,可以单独的检查每一个观察者和模型,减少复杂性。

image

 

 

3.8预防未知问题

posted @ 2013-03-03 15:18 Enic 阅读(265) | 评论 (0)编辑 收藏

1 : VS2005的STL性能不佳,请改用新的编译器测试,例如VS2010或VS2012或minGW4.7
如果使用mingw,记得让编译器支持c++11。
insert资料的时候善用emplace_back(可以保证就地construct,而非copy再construct)
不过我用mingw4.6的时候,map和set似乎还不支援这项功能
2 :  AVL树可能和stl的map或set的资料结构不同(red black tree),虽然两者很象啦
http://bbs.csdn.net/topics/390369473?page=2
posted @ 2013-02-26 13:21 Enic 阅读(373) | 评论 (0)编辑 收藏

×少量的预防措施要比大量的治疗措施有价值的多。。。

 

1.故障从哪里来

为了寻找有缺陷的代码,你必须以这个故障作为起点回溯追踪起因。

1.2从缺陷到故障

通常缺陷是通过以下四个阶段产生的:

1.程序员制造了一个缺陷:所有代码都是程序员写的,写错了。

2.缺陷造成了错误状态的感染:正确的代码段,被错误的代码感染。这时候代码已经不可控。

3.错误状态不断的传播:大多数程序由于不正确的输入而返回错误,当后面的程序访问该状态时,会把错误扩散到后续的程序状态中。(正确情况应该是不会持续传播的,应该会被后续某个模块覆盖或者修正)

4.错误状态引发的故障:外部程序应为感知到了程序的错误状态而故障

×错误只能程序有缺陷,不能证明程序没有缺陷。。。

 

1.3迷失在时空之中

调试过程可以分解成七个步骤:

1.track the problem

2.reproduce the failure

3.automate and simplify

4.find infection origins

5.focus on likely origins

6.isolate the infection chain

7.correct the defect

 

在很大程度上,调试就是一个搜索问题,主要是如下两个原则:

×从错误状态中分离出正确状态:如果一个状态是错误的,它可能就是从缺陷到故障的传播链中的一部分;如果一个状态是正确的,他就基本不可能有错误被传播。

×从不相关状态中分离出相关状态:一个变量的值取决于一小部分早期变量的值。因此,只有一部分早期状态是和程序故障相关的。

 

1.4从故障到修正

×跟踪问题:

×重现故障:

×自动化和简化测试用例:如果是一个复杂的程序,就必须考虑如何自动产生故障(应为希望被重现),以及如何简化输入,得到最小测试用例。

×寻找可能的感染源:如果有自动化测试可以使用排除法,将测试数据中会导致错误的数据找到。

×分离感染源:假设找到是某个测试数据导致错误,现在可以回溯相关系统这个数据出来的模块。

×修正缺陷:

 

1.5自动调试技术

×简化输入:

×程序片段:

×观察状态:

×监视状态:

×断言:

×反常:

×因果链:

 

1.6 BUG、失误、还是缺陷

缺陷(defect):错误的程序代码(代码中的bug)

错误的状态感染(infection): 错误的程序状态(状态中的bug)

故障(failure): 可感知程序的错误行为(行为中的bug)

 

summary:

1.调试程序的七个步骤:跟踪->重现->自动化->发现感染源->重点关注->分离->修正

咱们平常就是自动化和分离的时候会偷懒,老实说,在调试复杂程序的时候,花点时间做自动化和分离是“磨刀不误砍柴功”

 

////////////////////////////////////////////////////////////////////////////////////////////////

        程序员写了一段有缺陷的代码,这是否意味着他犯了过错呢?考虑这些情况:

原始需求没有预测到未来的变化,如:千年虫

只有当程序的某种行为呈现在用户面前是时,才有可能被列入“故障”

在模块化的程序中,故障可能是由两个模块之间的不兼容接口造成的。

分布式系统中,故障可能是由几个组件之间无法预测的交互造成的

。。。。。。

这时候讨论责任已然是一种政治态度

////////////////////////////////////////////////////////////////////////////////////////////////

 

////////////////////////////////////////////////////////////////////////////////////////////////

/////  f16的bug

image

////////////////////////////////////////////////////////////////////////////////////////////////

image

////////////////////////////////////////////////////////////////////////////////////////////////

posted @ 2013-02-23 14:58 Enic 阅读(363) | 评论 (0)编辑 收藏

final 修饰 class member just like const in c++;

synchronized means thread safe

 

final 修饰成员变量相当于cpp中的const修饰

synchronized 相当于是声明原子操作,同一个对象的不同synchronized语句块是线程安全的,是synchrony的,,,

posted @ 2013-02-23 14:49 Enic 阅读(218) | 评论 (0)编辑 收藏

渲染 渲染缓存 混合 像素格式混合 基础渲染器 顶点源 路径存储器
渲染器:渲染器负责表现“扫描线”中的每个线段。在渲染器之前AGG图形中的线段
是没有颜色值的,只是位置、长度、和透明度。渲染器赋予线段色彩,最终成为一副
完整的图像。
最常用的如下:像素格式渲染器-PixelFormatRenderer、基础渲染器-BaseRender、扫描线(抗锯齿)ScanlineRenderer渲染器 
像素格式渲染器可以直接工作
基础渲染器需要像素格式作为模版支持
扫描渲染器需要基础渲染器作为模版支持
渲染缓存:渲染缓存保存着一个个像素,作为AGG的画布。它仅仅是一个内存块,用来存储像素,
不提供任何绘图功能,只允许你读取和修改里边的数据。它也不告诉你里边的像素类型---它只管理内存
混合器:混合器是用来处理不同像素格式的如:agg::rgba  agg::argb(PS:也许叫像素点混合器比较合适)
像素格式混合器:如agg::pixfmt_rgb24。(像素块混合器?)像素格式混合器的作用是直接操作像素,也就是
在缓存里边保持的数据。像素格式有两个属性决定:混合器类型(RGBA32)和顺序(ORDER_ARGB)
基础渲染器:基础渲染器是扫描线渲染器的基础。基础渲染器需要手动以模版的形式系统像素格式信息,
他会通过像素格式混合器来渲染。(实际通过模版传入的好像是像素格式混合器)他的功能比像素格式混合器来的
要更全面一点,有更多的渲染接口。
顶点源:顶点源是一个concept,有rewind()和vertex()函数。

********************
参考教程
http://www.360doc.com/content/12/0722/09/992979_225748412.shtml

posted @ 2013-02-20 14:56 Enic 阅读(255) | 评论 (0)编辑 收藏

仅列出标题
共22页: First 14 15 16 17 18 19 20 21 22