Boost logo

Boost Users :

Subject: Re: [Boost-users] [Statechart] Why does this state machine enter unstable state only in debug mode?
From: Zhu Bicen (zhubicen_at_[hidden])
Date: 2011-03-23 02:55:46


I know Andreas Huber replied me, Thank you!
but I just see the reply from Boost-user Digest,
I don't know how to reply on that kind of mail loop. Sorry , I reply here.

To reproduce this issue, after launching the GUI, the menu"help->About"
should be clicked.
And make sure the file path in the code is actually existing and has .mp3
type.

Finally I found the cause:
This issue is caused by the "Windows procedure can be reentrant" but the
process_event
can't.
When I call MciWndPlay in the windows procedure another msg is generated by
this call
and windows try to process this new message in the same Windows procedure
call, this
cause the fsm entered a unstable state.

2011/3/19 Zhu Bicen <zhubicen_at_[hidden]>

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

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