
お世話になります
無線機とGPSセンサーをCOMPORTでつないで操作やモニターするソフトを作成してまして
煮詰まってしまったので質問させていただきます。
無線機に設定をした際や読みこみリクエストを送った際に無線機からの返事を
取りこぼしてしまうことがあり受信を別スレッドにすれば解決するのかと思って
改良途中です。
まず手始めにGPSセンサーをCOMPORTをつないでいてGPSセンサーの受信を
別スレッドで動かしてます。
なんとか別スレッドで動くところまで来たのですがスレッドの終了処理が
わからないでいます。
ダイアログに
”GPS_ENABLE”
というボタンがありそれを押すと受信および表示→受信停止表示クリア→受信および表示
を繰り返すようにしてます。
色々いじってみたのですがGPS読み込み時に”GPS_ENABLE”を
押して終了しようとすると例外がスローされてしまいます。
ハンドルされない例外が 0x7682B5B2 で発生しました (FT991REMOTE.exe 内):
Microsoft C++ の例外: CMemoryException (メモリの場所 0x0587ECA4)。
例外がスローされました:読み取りアクセス違反。
pOb-> が 0xDDDDDDDD でした。
だいたい上記の2つのどちらかが出る感じです
ソースを提示します
よろしくお願いします
// FT991REMOTEDlg.h : ヘッダー ファイル
static UINT AFX_CDECL ThreadProc_GPS(LPVOID pParam);
~~~~~
// GetGPS.h : ヘッダー ファイル
static UINT __cdecl CALL_GPS_READ_Thread(LPVOID pData);
int READ_ROOP;//READのループ可否
~~~~~
// FT991REMOTEDlg.cpp : 実装ファイル
~
GetGPS* GetGPS1 = new GetGPS();
CWinThread* GPS_pThread;
~
BOOL CFT991REMOTEDlg::OnInitDialog()
{
~~~~~
GetGPS1->GPS_Flag = 0; //GPS読みだし有効無効
////////////////////////////////////////////////////////////
//タイマー設定//////////////////////////////////////////////
////////////////////////////////////////////////////////////
UINT timerID = 1;
UINT interval = 10;
m_timerID = SetTimer(timerID, interval, NULL);
// タイマーを設定できない場合
if (m_timerID == 0)
{
AfxMessageBox(_T("タイマーを設定できませんでした。"));
}
return TRUE; // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
~~~~~
}
void CFT991REMOTEDlg::OnTimer(UINT_PTR nIDEvent)
{
~~~~~
if ( (m_timerID == 1) && (NowCOMMAND_Set == 0 ) )
{
if (GetGPS1->GPS_Flag == 1)
{
CFT991REMOTEDlg::GPS_CALL_Read();//GPS内容表示
}
}
~~~~~
}
//GPS読み込み開始終了ボタン
void CFT991REMOTEDlg::OnBnClicked_GPS_Enable()
{
int Ret = 0;
if (GetGPS1->GPS_Flag == 0)//開始処理
{
Ret = GetGPS1->GetComport_CFG(_T("GPS.ini"));//GPSrs23cのコンフィグゲット及び初期化
if (Ret == TRUE)
{
GetGPS1->READ_ROOP = TRUE;//READのループ可否
GetGPS1->GPS_Flag = 1;
GetGPS1->OLD_GL_DATA = _T("");
GetGPS1->GL_DATA = _T("");
GPS_pThread = AfxBeginThread(GetGPS::CALL_GPS_READ_Thread, GetGPS1); // 重い処理をワーカースレッドで処理
}
}
else if (GetGPS1->GPS_Flag != 0)//終了処理
{
GetGPS1->READ_ROOP = FALSE;//READのループ可否
GetGPS1->GPS_Flag = 0;
GetGPS1->OLD_GL_DATA = _T("");
GetGPS1->GL_DATA = _T("");
GPS_pThread->Delete();//スレッドの終わらせ方このへんがあわからない
AfxEndThread(0, 1);//スレッドの終わらせ方このへんがあわからない;
CloseHandle(GetGPS1->ComPort5); // シリアルポートを閉じる
}
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
GetGPS.cpp
int GetGPS::GetComport_CFG(CString CFG_FILE)
{
省略
ComPort5 = CreateFile(_T("\\\\.\\COM8"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); // シリアルポートを開く
);
Ret = PurgeComm(//消去
ComPort5,//通信デバイスのハンドル:CreateFile()で取得したハンドルを指定
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR
);
if (Ret == FALSE)//失敗した場合
{
printf("PurgeComm failed.\n");
CloseHandle(ComPort5);
message = _T("COMOPORTが開けません");
AfxMessageBox(message);
//exit(0);
return FALSE;
}
return TRUE;
}
//COMPORTから読み込み
int GetGPS::Readrs232c(CString* RS_SD, CString* RS_RD)//RS232C受信
{
int Ret;
RwRs232TimeOutSet();//タイムアウトの設定
Sleep(600); //
DWORD errors; // エラーが起きた場合、エラーコードが入る
COMSTAT comStat; // 通信状態バッファ
ClearCommError(ComPort5, &errors, &comStat); // 入出力バッファの情報を通信状態バッファへ取り込む
CString SSD, RRD;//引数のローカル変数利用
char* recievedData = new char[comStat.cbInQue];
DWORD NumberOfBytesRead = 0;
Ret = ReadFile(ComPort5, recievedData, comStat.cbInQue, &NumberOfBytesRead, NULL); // 受信バッファからデータバッファへ取り込む
No.3ベストアンサー
- 回答日時:
作業スレッドの終了待ちは
WaitForSingleObject(GPS_pThread, INFINITE);
のようですね。ただし作業スレッドが終了しないと帰ってこない。
あと作業スレッドは終了すると自オブジェクトを削除しているかもしれない。そうするとGPS_pThread->Delete();は要らず、単にGPS_pThread=NULL;で良い。
下記によるとスレッド終了後に終了コードを取得する場合は
> m_bAutoDeleteデータメンバーを FALSE に設定します。これにより、CWinThread オブジェクトは、スレッドが終了した後も残ります。
とある。逆に言うとm_bAutoDelete=FALSEをしていない場合はスレッド終了時にオブジェクトが削除されるということ。
# https://docs.microsoft.com/ja-jp/cpp/parallel/mu …
あと参考までに MFCでスレッド処理を行う サンプル
# https://www.paveway.info/entry/2018/11/27/mfc_th …
このコードではスレッドは終了時に自分で終了メッセージを主スレッドに送っているので、主スレッドでスレッド終了イベントが捕まえられる。
お世話になります
rinkun様 ご回答ありがとうございます
すみません返信が逆になってしまいました。
こちらさ先です
色々とアドバイスをいただき感謝します
確かに省略しているところではRS232Cの読み込みを行ってます。
RS232Cの読み込みではデータがたまるのを待つためSleep(700)で
待機してました
上のRS232Cの読み込み処理が終わってから
forの下部の方でbreakさせているので再びRS232Cを読みに行くことはないと思って
大丈夫かと思ってましたがそれがうまくいかない原因だったのかもしれません。
取り急ぎかなり適当にいじりましたがなんとか例外が出なくなったようです
GPS_Read関数内
for(;;)
{
~~~~~~~~~
if (READ_ROOP == FALSE)
{
int ret;
ret = PurgeComm(//消去
ComPort5,//通信デバイスのハンドル:CreateFile()で取得したハンドルを指定
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR
// 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定
);
GPS_Flag = 0;//このフラッグが0だとRS232Cを読みに行きません
CloseHandle(ComPort5); // シリアルポートを閉じるをここにもってきました
Sleep(1000);//ここで待たせるようにしました。
AfxEndThread(0, 1);
break;
}
No.2
- 回答日時:
うーん、GPS_Readのforループ中の省略されたコードでCOMポートを読んでいるのですよね。
これの待ち時間によってはフラグREAD_LOOPをチェックする周期が長すぎて想定外になります。あとフラグREAD_LOOPを立てた主スレッドの方は、その後に作業スレッド終了を待機しないとオブジェクトの削除時点で作業スレッドが終了していることを保証できません。質問のコードはこれが問題ですね。フラグを立てた数行後にオブジェクト削除していて、その間にシステムコールを呼びそうなコードが含まれていないので、作業スレッドが動作する隙もありません。スレッドは多くの場合、システムコールが呼ばれたタイミングで切り替わります。
スレッドの終了を待機するメソッドが用意されているはずなのでフラグを立てたらそれを呼んでスレッド終了を待って下さい。なお作業スレッドがフラグをチェックする周期が長い場合、このコードを入れると主スレッドの応答がなくなる場合がありますので注意下さい。
GUIの主スレッドなら作業スレッド終了でイベントが起きるようにしてフラグを立てて帰り、別途、作業スレッド終了イベントでオブジェクトを削除する方が安全です。
フラグREAD_LOOPは単なる変数でなくスレッド間通信機能のオブジェクトの方が安心ですが、このコードの例だと単なる変数でも動作はするでしょう。
void CFT991REMOTEDlg::OnBnClicked_GPS_Enable()
{
~~~~~~~~~
else if (GetGPS1->GPS_Flag != 0)
{
~~~~~~~~~
GetGPS1->READ_ROOP = FALSE;//READのループ可否
GetGPS1->GPS_Flag = 0;
GetGPS1->OLD_GL_DATA = _T("");
GetGPS1->GL_DATA = _T("");
//GPS_pThread->Delete();//これを残しておくと例外発生
GPS_pThread = NULL;
//AfxEndThread(0, 1);//これも←実際にループしてる場所で書く
// CloseHandle(GetGPS1->ComPort5); // シリアルポートを閉じる←GPS_Read関数へ移動
}
}
確かに消したものをまた消す行為が悪かったと思います
下記のように変更でよくなりました
//GPS_pThread->Delete();//例外でる
GPS_pThread = NULL;
更にこちらも変更して効いたようです
GetGPS1->GPS_Flag = 0;
CloseHandle(GetGPS1->ComPort5); // シリアルポートを閉じる←GPS_Read関数へ移動
あと今更ですがずーと繰り返すfor内に宣言してるところがこれもまずかったかと思い外で宣言するようにしました。
for(;;)
{
int a;//これだといけないのかと思い外に出しました
CString b;
}
イベントについてはなかなか理解が追い付かずこれから徐々に対策いようかと思います。
No.1
- 回答日時:
長々としたソースをちゃんと読んではいませんが、おそらく作業スレッドが動いたままスレッドが使うオブジェクトを削除して破棄済みメモリにアクセスしているのでしょう。
まず一般論として(プロセスもそうですが)スレッドを外部から強制的に安全に止めることは出来ません。なので安全に止めたければ作業スレッドの処理中に定期的にフラグチェックを入れて、止めたい時には主スレッドがフラグを立てて作業スレッドはフラグチェック時点で停止指示があれば自分で終了します。厳密にはフラグもただの変数でなくイベントなどのスレッド間通信機能を使います。スレッドが使うオブジェクトは、スレッドが停止したことを確認して主スレッド側で削除します。
それと主スレッドと作業スレッドのデータのやりとりはどうしていますか? この辺も下手をするとメモリリークの原因になるので、よぼど多数のスレッドを作るとか効率優先でなければ作業スレッドでなく作業プロセスにしてデータもプロセス間通信でやりとりする方が安全です。
お世話になります
rinkun様 ご回答ありがとうございます
読み込んだデータの受け渡しは
クラスGetGPSのグローバル変数を読んでそちらを
FT991REMOTEDlgで表示しています。
GetGPS1->Ido_Keido
などのデータを表示してます
GPS_Read()がぐるぐる回ってまして
FT991REMOTEDlgで READ_ROOP を FALSE
にして GPS_Read()を抜けるようにしたつもりでした
安直にfor文の最後の方で抜ければうまくいくかと思いましたが
甘かったようです。
おっしゃってるように
破棄済みメモリにアクセスしているみたいなのですが
この辺の後処理がよくわかりません。
イベントなどのスレッド間通信機能もよく理解してませんので
GetGPS1のグローバル変数をいじって止めようとしてました
//////////////////////////////
//GPS読み込み成形処理////////////////////////////
//////////////////////////////
int GetGPS::GPS_Read()
{
for(;;)
{
COMPORT読み込み処理
読み込んだデータを計算整形し
グローバル変数に記録
~~~~~~~~~~~
if (READ_ROOP == FALSE)
{
int ret;
ret = PurgeComm(//消去
ComPort5,//通信デバイスのハンドル:CreateFile()で取得したハンドルを指定
PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR
// 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定
);
AfxEndThread(0, 1);
break;
}
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript WordPressのコンタクトフォーム7にて送信者の位置情報を送らせたい 2 2022/09/14 23:28
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- 大学・短大 (工学部)成績について 3 2022/09/07 14:16
- iPad IPAD mini6 GPSモデルは通信契約がないと機能しないもの? 5 2022/06/26 17:53
- PHP ここでの ②if($su_d<>"")の比較演算子 を使う理由は 1 2022/03/26 02:33
- Visual Basic(VBA) 【Excel VBA】自動メール送信の機能追加 5 2022/09/29 12:53
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- PHP if(preg_match("/[^0-9]/",$gu_d)){意味を教えてください。 1 2022/05/06 05:37
- Visual Basic(VBA) エクセルVBAで教えて頂きたいのですが? 2 2022/12/31 20:28
- C言語・C++・C# TCP/IP通信時のサーバーからの受信 2 2022/11/23 09:11
このQ&Aを見た人はこんなQ&Aも見ています
-
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
VC++スレッドの正しい終了のさせかた
C言語・C++・C#
-
MFCのワーカースレッドとUIスレッドの使い分け
C言語・C++・C#
-
-
4
画面を強制的に再描画させる方法
C言語・C++・C#
-
5
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
6
MFCでハンドルを取得するには
C言語・C++・C#
-
7
WaitForSingleObjectの使い方について
C言語・C++・C#
-
8
C++言語で、構造体のコピーは可能(しても良い)のでしょうか?
C言語・C++・C#
-
9
CStringの文字列検索&抜き出しについて
C言語・C++・C#
-
10
読み込み中にアクセス違反が発生しました、と出ます。これを回避することは
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
マルチスレッド内のループについて
-
クラス内でのpthread_createに...
-
VC++スレッドの正しい終了のさ...
-
pthread_attr_tへの値の代入に...
-
[Windowsプログラミング] スレ...
-
別スレッドのデータを受信できない
-
スレッドにて同一メモリの書き...
-
CWnd::OnTimerのスレッドの取得
-
別スレッドからメインダイアロ...
-
スレッド終了を待つ間に開放さ...
-
pthread_cond_wait 取りこぼし?
-
スレッドの名前の取得について
-
スレッドの安全な終了のさせ方
-
スレッドの監視方法
-
スレッドの終了の仕方
-
スレッドがサスペンドされてい...
-
スレッドの監視方法について
-
Macターミナルで実行中のプログ...
-
トラックバック機能を作りたい
-
バックグラウンドのプロセスの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
スレッドの監視方法について
-
VC++スレッドの正しい終了のさ...
-
スレッドにて同一メモリの書き...
-
スレッドの終了の仕方
-
VB2005 シリアル通信のClose処理
-
WaitForSingleObjectの使い方に...
-
別スレッドのデータを受信できない
-
同一スレッドで、ロックをかけ...
-
CWnd::OnTimerのスレッドの取得
-
スレッドの安全な終了のさせ方
-
メインダイアログが最背面に表...
-
スレッド一覧の取得
-
Windows上で、シグナル(SIGTERM...
-
C言語で一定時間待機後、再実行
-
C#でスレッド実行中のイベント...
-
複数スレッドを動作させるのに...
-
.netアプリへのSendMessageでフ...
-
DirectX LPDIRECT3DDEVICE9のマ...
-
スレッド内でコントロールやWin...
-
DirectX 11のConsntanBuffer
おすすめ情報