|
Boost Users : |
Subject: [Boost-users] [Statechart] Why does this state machine enter unstable state only in debug mode?
From: Zhu Bicen (zhubicen_at_[hidden])
Date: 2011-03-18 22:21:03
I am trying to use statechart in a player application. And found
a weird issue,
so I write following code to reproduce the issue and ask for help.
1. call the MciWndPlay win32API to play a music file within a state entry
action
2. Windows msg , which indicate the player current player position, is
coming
3. call process_event within Windows procedure
4. but assert failed: get_pointer(pOutermostUnstableState_) == 0
It seems the PlayingState entry action does not execute completely,
The debug message after MciWndPlay call is not also printed out, but
another event is coming,
But This is a single thread application,
the MciWndPlay is just Send Message to something and return immediately.
I also print out the thread ID, all is the same.
Another thing is this assert failure is only occurred in Debug Mode, in
release mode all goes well.
I am using Visual C++ 2008 express, and boost 1.46.1.
Any comments and indication is welcome. I am confused by this issue several
days.
Thanks in advance.
// BugFix.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "BugFix.h"
#include "Vfw.h"
#include <iostream>
#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/result.hpp>
#include <mmsystem.h>
#pragma comment(lib, "vfw32.lib")
namespace fsm = boost::statechart;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
std::wstring file_name = L"D:\\VOA\\5. Deep Six It Is Well Hidden.mp3";
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
static std::wstring FILE_NAME = L"";
struct OpenFileEvent: public fsm::event< OpenFileEvent >{
std::wstring file_name;
OpenFileEvent(const std::wstring p_file_name):file_name(p_file_name){}
};
struct UpdatePosEvent: public fsm::event< UpdatePosEvent >{
long pos;
UpdatePosEvent(long position): pos(position){}
};
class WaitingForFileState;
class PlayingState;
class PlayerFsm : public fsm::state_machine< PlayerFsm, WaitingForFileState
>
{
public:
friend class WaitingForFileState;
friend class HandlingFileState;
friend class PlayingState;
};
class WaitingForFileState:
public fsm::simple_state< WaitingForFileState, PlayerFsm >
{
public:
typedef fsm::custom_reaction< OpenFileEvent > reactions;
fsm::result react( const OpenFileEvent& evt)
{
std::cout << "OpenFileEvent is received " << std::endl;
FILE_NAME = evt.file_name;
return transit< HandlingFileState >();
}
};
class HandlingFileState:
public fsm::state< HandlingFileState, PlayerFsm, PlayingState>
{
public:
HandlingFileState( my_context ctx ): my_base( ctx){
MCIWndOpen(_playerWnd, FILE_NAME.c_str(), NULL);
}
};
class PlayingState:
public fsm::simple_state< PlayingState, HandlingFileState>
{
public:
PlayingState() {
std::cout << "Entering PlayingState" << std::endl;
std::cout << "fsm threadId = " << GetCurrentThreadId() << std::endl;
assert(MCIWndPlay(_playerWnd) == 0);
// below message is not printed out in debug mode,
// and another message UpdatePosEvent come
// and StateChart assert failure
std::cout << "After MCIWndPlay" << std::endl;
}
typedef fsm::custom_reaction< UpdatePosEvent > reactions;
fsm::result react( const UpdatePosEvent& evt){
std::cout << "UpdatePosEvent is received in PlayingState" <<
std::endl;
return fsm::detail::result_utility::
make_result( fsm::detail::consumed );
}
private:
long current_pos_;
};
HWND _playerWnd;
PlayerFsm _player_fsm;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
AllocConsole();
freopen("CONOUT$", "w+t", stdout);
freopen("CONOUT$", "w+t", stderr);
std::cout << "threadId = " << GetCurrentThreadId() << std::endl;
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_BUGFIX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BUGFIX));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BUGFIX));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_BUGFIX);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance,
NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
_player_fsm.process_event(OpenFileEvent(file_name));
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
_player_fsm.initiate();
_playerWnd = MCIWndCreate(
hWnd,
hInst,
MCIWNDF_NOTIFYPOS|MCIWNDF_NOMENU|MCIWNDF_NOTIFYMODE,
NULL);
break;
case MCIWNDM_NOTIFYPOS:
std::cout << "received MCIWNDM_NOTIFYPOS msg, threadId = "
<< GetCurrentThreadId() << std::endl;
_player_fsm.process_event(UpdatePosEvent(lParam));
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
-- Best Regards Bicen Zhu
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net