Skip to content

Commit 219727d

Browse files
authored
Merge pull request #85 from katahiromz/copilot/fix-cancellation-issues
Add event-based cancellation manager for stable state restoration
2 parents 60bf317 + 3574429 commit 219727d

8 files changed

Lines changed: 217 additions & 12 deletions

XG_CancelGenBlacksDialog.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "XG_Window.hpp"
4+
#include "XG_CancellationManager.hpp"
45

56
// キャンセルダイアログ。
67
class XG_CancelGenBlacksDialog : public XG_Dialog
@@ -9,6 +10,7 @@ class XG_CancelGenBlacksDialog : public XG_Dialog
910
const DWORD SLEEP = 250;
1011
const DWORD INTERVAL = 300;
1112
const UINT uTimerID = 999;
13+
XG_CancellationManager m_cancellation_manager;
1214

1315
XG_CancelGenBlacksDialog() noexcept
1416
{
@@ -22,8 +24,15 @@ class XG_CancelGenBlacksDialog : public XG_Dialog
2224
::EnterCriticalSection(&xg_csLock);
2325
xg_bCancelled = true;
2426
::LeaveCriticalSection(&xg_csLock);
25-
// スレッドを待つ。
26-
XgWaitForThreads();
27+
// スレッドを待つ(タイムアウト付き)。
28+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
29+
// タイムアウトの場合は通常の待機。
30+
XgWaitForThreads();
31+
}
32+
// キャンセル時に初期状態に復元。
33+
m_cancellation_manager.RestoreOnCancel();
34+
// グローバルポインタをクリア。
35+
xg_pCancellationManager = nullptr;
2736
// スレッドを閉じる。
2837
XgCloseThreads();
2938
}
@@ -32,6 +41,12 @@ class XG_CancelGenBlacksDialog : public XG_Dialog
3241
{
3342
// ダイアログを中央へ移動する。
3443
XgCenterDialog(hwnd);
44+
// リセット。
45+
m_cancellation_manager.Reset();
46+
// 初期状態を保存。
47+
m_cancellation_manager.SaveInitialState();
48+
// グローバルポインタを設定。
49+
xg_pCancellationManager = &m_cancellation_manager;
3550
// 解を求めるのを開始。
3651
XgStartGenerateBlacks();
3752
// リトライ回数をリセット。

XG_CancelSmartSolveDialog.hpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "XG_Window.hpp"
4+
#include "XG_CancellationManager.hpp"
45

56
// キャンセルダイアログ(スマート解決)。
67
class XG_CancelSmartSolveDialog : public XG_Dialog
@@ -9,6 +10,7 @@ class XG_CancelSmartSolveDialog : public XG_Dialog
910
const DWORD SLEEP = 250;
1011
const DWORD INTERVAL = 300;
1112
const UINT uTimerID = 999;
13+
XG_CancellationManager m_cancellation_manager;
1214

1315
XG_CancelSmartSolveDialog() noexcept
1416
{
@@ -19,6 +21,12 @@ class XG_CancelSmartSolveDialog : public XG_Dialog
1921
// タイマーを解除する。
2022
::KillTimer(hwnd, uTimerID);
2123
xg_dwlTick1 = ::GetTickCount64();
24+
// リセット。
25+
m_cancellation_manager.Reset();
26+
// 初期状態を保存。
27+
m_cancellation_manager.SaveInitialState();
28+
// グローバルポインタを設定。
29+
xg_pCancellationManager = &m_cancellation_manager;
2230
XgStartSolve_Smart();
2331
// タイマーをセットする。
2432
::SetTimer(hwnd, uTimerID, INTERVAL, nullptr);
@@ -32,16 +40,36 @@ class XG_CancelSmartSolveDialog : public XG_Dialog
3240
::EnterCriticalSection(&xg_csLock);
3341
xg_bCancelled = true;
3442
::LeaveCriticalSection(&xg_csLock);
35-
// スレッドを待つ。
36-
XgWaitForThreads();
43+
// スレッドを待つ(タイムアウト付き)。
44+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
45+
// タイムアウトの場合は通常の待機。
46+
XgWaitForThreads();
47+
}
48+
// キャンセル時に初期状態に復元。
49+
m_cancellation_manager.RestoreOnCancel();
50+
// グローバルポインタをクリア。
51+
xg_pCancellationManager = nullptr;
3752
// スレッドを閉じる。
3853
XgCloseThreads();
3954
}
4055

4156
void DoRetry(HWND hwnd)
4257
{
43-
// キャンセルする。
44-
DoCancel(hwnd);
58+
// タイマーを解除する。
59+
::KillTimer(hwnd, uTimerID);
60+
// キャンセルしてスレッドを待つ。
61+
::EnterCriticalSection(&xg_csLock);
62+
xg_bCancelled = true;
63+
::LeaveCriticalSection(&xg_csLock);
64+
// スレッドを待つ(タイムアウト付き)。
65+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
66+
// タイムアウトの場合は通常の待機。
67+
XgWaitForThreads();
68+
}
69+
// グローバルポインタをクリア(リトライ時は状態復元しない)。
70+
xg_pCancellationManager = nullptr;
71+
// スレッドを閉じる。
72+
XgCloseThreads();
4573

4674
::InterlockedIncrement(&xg_nRetryCount);
4775
Restart(hwnd);

XG_CancelSolveDialog.hpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "XG_Window.hpp"
4+
#include "XG_CancellationManager.hpp"
45

56
// キャンセルダイアログ。
67
class XG_CancelSolveDialog : public XG_Dialog
@@ -9,6 +10,7 @@ class XG_CancelSolveDialog : public XG_Dialog
910
const DWORD SLEEP = 250;
1011
const DWORD INTERVAL = 300;
1112
const UINT uTimerID = 999;
13+
XG_CancellationManager m_cancellation_manager;
1214

1315
XG_CancelSolveDialog() noexcept
1416
{
@@ -17,6 +19,12 @@ class XG_CancelSolveDialog : public XG_Dialog
1719
void Restart(HWND hwnd) noexcept
1820
{
1921
xg_dwlTick1 = ::GetTickCount64();
22+
// リセット。
23+
m_cancellation_manager.Reset();
24+
// 初期状態を保存。
25+
m_cancellation_manager.SaveInitialState();
26+
// グローバルポインタを設定。
27+
xg_pCancellationManager = &m_cancellation_manager;
2028
// 解を求めるのを開始。
2129
XgStartSolve_AddBlack();
2230
// タイマーをセットする。
@@ -31,8 +39,15 @@ class XG_CancelSolveDialog : public XG_Dialog
3139
::EnterCriticalSection(&xg_csLock);
3240
xg_bCancelled = true;
3341
::LeaveCriticalSection(&xg_csLock);
34-
// スレッドを待つ。
35-
XgWaitForThreads();
42+
// スレッドを待つ(タイムアウト付き)。
43+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
44+
// タイムアウトの場合は通常の待機。
45+
XgWaitForThreads();
46+
}
47+
// キャンセル時に初期状態に復元。
48+
m_cancellation_manager.RestoreOnCancel();
49+
// グローバルポインタをクリア。
50+
xg_pCancellationManager = nullptr;
3651
// スレッドを閉じる。
3752
XgCloseThreads();
3853
}
@@ -46,8 +61,13 @@ class XG_CancelSolveDialog : public XG_Dialog
4661
::EnterCriticalSection(&xg_csLock);
4762
xg_bCancelled = true;
4863
::LeaveCriticalSection(&xg_csLock);
49-
// スレッドを待つ。
50-
XgWaitForThreads();
64+
// スレッドを待つ(タイムアウト付き)。
65+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
66+
// タイムアウトの場合は通常の待機。
67+
XgWaitForThreads();
68+
}
69+
// グローバルポインタをクリア(リトライ時は状態復元しない)。
70+
xg_pCancellationManager = nullptr;
5171
// スレッドを閉じる。
5272
XgCloseThreads();
5373

XG_CancelSolveNoAddBlackDialog.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "XG_Window.hpp"
4+
#include "XG_CancellationManager.hpp"
45

56
// キャンセルダイアログ(黒マス追加なし)。
67
class XG_CancelSolveNoAddBlackDialog : public XG_Dialog
@@ -9,6 +10,7 @@ class XG_CancelSolveNoAddBlackDialog : public XG_Dialog
910
const DWORD SLEEP = 250;
1011
const DWORD INTERVAL = 300;
1112
const UINT uTimerID = 999;
13+
XG_CancellationManager m_cancellation_manager;
1214

1315
XG_CancelSolveNoAddBlackDialog() noexcept
1416
{
@@ -17,6 +19,12 @@ class XG_CancelSolveNoAddBlackDialog : public XG_Dialog
1719
void Restart(HWND hwnd) noexcept
1820
{
1921
xg_dwlTick1 = ::GetTickCount64();
22+
// リセット。
23+
m_cancellation_manager.Reset();
24+
// 初期状態を保存。
25+
m_cancellation_manager.SaveInitialState();
26+
// グローバルポインタを設定。
27+
xg_pCancellationManager = &m_cancellation_manager;
2028
// スマート解決なら、黒マスを生成する。
2129
XgStartSolve_NoAddBlack();
2230
// タイマーをセットする。
@@ -31,8 +39,15 @@ class XG_CancelSolveNoAddBlackDialog : public XG_Dialog
3139
::EnterCriticalSection(&xg_csLock);
3240
xg_bCancelled = true;
3341
::LeaveCriticalSection(&xg_csLock);
34-
// スレッドを待つ。
35-
XgWaitForThreads();
42+
// スレッドを待つ(タイムアウト付き)。
43+
if (!m_cancellation_manager.WaitForCompletion(5000)) {
44+
// タイムアウトの場合は通常の待機。
45+
XgWaitForThreads();
46+
}
47+
// キャンセル時に初期状態に復元。
48+
m_cancellation_manager.RestoreOnCancel();
49+
// グローバルポインタをクリア。
50+
xg_pCancellationManager = nullptr;
3651
// スレッドを閉じる。
3752
XgCloseThreads();
3853
}

XG_CancellationManager.hpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//////////////////////////////////////////////////////////////////////////////
2+
// XG_CancellationManager.hpp --- Cancellation Manager
3+
// Copyright (C) 2012-2020 Katayama Hirofumi MZ. All Rights Reserved.
4+
// (Japanese, UTF-8)
5+
6+
#pragma once
7+
8+
#include "XWordGiver.hpp"
9+
10+
//////////////////////////////////////////////////////////////////////////////
11+
// キャンセル管理クラス(軽量設計、実行速度への影響を最小化)
12+
// Lightweight cancellation manager to ensure stable state during cancellation
13+
// without impacting execution speed.
14+
15+
class XG_CancellationManager
16+
{
17+
private:
18+
HANDLE m_hCompletionEvent; // 完了通知用イベント(completion event for thread waiting only)
19+
XG_Board m_initial_board; // 初期状態(復元用)(initial state for restoration)
20+
21+
public:
22+
// コンストラクタ
23+
XG_CancellationManager() noexcept
24+
: m_hCompletionEvent(nullptr)
25+
{
26+
// 手動リセット、初期状態は非シグナル状態のイベントを作成
27+
// Create manual-reset event, initially non-signaled
28+
m_hCompletionEvent = ::CreateEventW(nullptr, TRUE, FALSE, nullptr);
29+
}
30+
31+
// デストラクタ
32+
~XG_CancellationManager() noexcept
33+
{
34+
if (m_hCompletionEvent != nullptr) {
35+
::CloseHandle(m_hCompletionEvent);
36+
m_hCompletionEvent = nullptr;
37+
}
38+
}
39+
40+
// 初期状態を保存
41+
// Save initial state for potential restoration
42+
void SaveInitialState() noexcept
43+
{
44+
m_initial_board = xg_xword;
45+
}
46+
47+
// 完了を通知(処理成功時)
48+
// Notify completion (on successful processing)
49+
void SetCompleted() noexcept
50+
{
51+
if (m_hCompletionEvent != nullptr) {
52+
::SetEvent(m_hCompletionEvent);
53+
}
54+
}
55+
56+
// 完了またはキャンセルを待機(タイムアウト付き)
57+
// Wait for completion or cancellation with timeout
58+
// Returns true if completed normally, false if timeout or cancelled
59+
bool WaitForCompletion(DWORD dwMilliseconds = 5000) const noexcept
60+
{
61+
if (m_hCompletionEvent == nullptr)
62+
return false;
63+
64+
DWORD dwResult = ::WaitForSingleObject(m_hCompletionEvent, dwMilliseconds);
65+
return (dwResult == WAIT_OBJECT_0);
66+
}
67+
68+
// キャンセル時に初期状態に復元
69+
// Restore initial state on cancellation
70+
void RestoreOnCancel() noexcept
71+
{
72+
// キャンセルされた場合のみ復元
73+
// Only restore if cancelled
74+
if (xg_bCancelled && !xg_bSolved) {
75+
xg_xword = m_initial_board;
76+
}
77+
}
78+
79+
// リセット(再利用時)
80+
// Reset for reuse
81+
void Reset() noexcept
82+
{
83+
if (m_hCompletionEvent != nullptr) {
84+
::ResetEvent(m_hCompletionEvent);
85+
}
86+
m_initial_board.clear();
87+
}
88+
89+
// コピー禁止
90+
XG_CancellationManager(const XG_CancellationManager&) = delete;
91+
XG_CancellationManager& operator=(const XG_CancellationManager&) = delete;
92+
};
93+
94+
//////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)