ReadDirectoryChangesWを別のスレッドで動かす

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
きたぐに

ReadDirectoryChangesWを別のスレッドで動かす

#1

投稿記事 by きたぐに » 1週間前

マルチスレッドのプログラミングに慣れようと思い、いろいろ試行錯誤しているのですが詰まってしまったため、質問させてください。
・WndProcからスレッドを作成して、そのスレッドにディレクトリを監視させます。ディレクトリはCode(WPARAM)と紐づけて、変更があった時にWndProcにメッセージを投げてそれを処理するというプログラムを書いているのですが、ヒープが壊れます(★★のところ)。原因はおそらく★を付けたところなのですが、どうしてそうなるかと、どのようにそれを回避するかがわかりません。対策法をご教示いただけると幸いです。
壊れたときの出力:
HEAP CORRUPTION DETECTED: after Normal block (#1176) at 0x00000043142539C0.
CRT detected that the application wrote to memory after end of heap buffer.

コード:

//スレッドメイン
void watcher::watcher_main( const size_t& Address )
{
	CHANDLE _hEvent;
	CHANDLE _hDict; //自動的にCloseHandleを呼び出す
	OVERLAPPED _Overlapped{ 0 };
	std::vector<UCHAR> _Buffer( 1024 * 64, 0 );
	DWORD _Size;

	(中略)
		if (!ReadDirectoryChangesW( _hDict, _Buffer.data(), _Buffer.size(),
			FALSE, _get()._info[Address].Info.Flags, nullptr, &_Overlapped, nullptr )) {
			_AtExit();
			break;
		}

		if (WaitForSingleObject( _hEvent, 600 ) == WAIT_TIMEOUT) {
			continue; //何もしない
		}

		_Size = 0;
		if (auto _Ret = GetOverlappedResult( _hDict, &_Overlapped, &_Size, FALSE );
				_Ret == FALSE || _Size == 0) {
			// 結果取得に失敗した場合
			std::wstring _Temp;
			const DWORD& Error = GetLastError();
			getErrorText( _Temp );
			trace << L"Buffer over " << ( _Size == 0 ) << L' ' << _Temp << L' ' <<  Error;
		}
		else {
			_get()._this.lock();
			auto _Entry = reinterpret_cast<FILE_NOTIFY_INFORMATION*>( _Buffer.data() );
			size_t _Offset = 0;
			while (true) {
				_get()._info[Address].Info.Buffer.emplace_back( _Entry->FileName,
					_Entry->FileNameLength / sizeof( WCHAR ), _Entry->Action ); //★
				if (_Entry->NextEntryOffset == 0) {
					break;
				}
				_Entry = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
					reinterpret_cast<unsigned char*>( _Entry ) + _Entry->NextEntryOffset );
			}

			trace << L"Sending Message To Main routine";
			//もう_get()にはさわらないのでアンロックする
			_get()._this.unlock();
			SendMessageW( _get()._hWnd, WM_MODIFIED_FILE, _get()._info[Address].Info.Code, 0 );
			_Buffer.clear();
		}

	}

	//Terminate
	_AtExit( false );
	_get()._info[Address].Status = status::terminate;
}
構造体

コード:

class wactcher {
	enum class file_action
	{
		created = FILE_ACTION_ADDED,
		removed = FILE_ACTION_REMOVED,
		modified = FILE_ACTION_MODIFIED,
		renamed_old_name = FILE_ACTION_RENAMED_OLD_NAME,
		renamed_new_name = FILE_ACTION_RENAMED_NEW_NAME
	};

	struct notify_info
	{
		std::wstring FileName; //変更されたファイル名
		file_action  Type;     //変更の種類

		notify_info( const notify_info& Left );
		notify_info( notify_info&& Right );
		notify_info( const WCHAR* Str,const size_t& Length, const DWORD& dwRowFileAction );
		~notify_info() noexcept;
	};
	//後略
}
//コンストラクタ(ムーブ・コピー・デストラクタは=defaultと同等の内容かと思われるので割愛)
watcher::notify_info::notify_info( const WCHAR* Str, const size_t& Length, const DWORD& dwRowFileAction ) :
	FileName( Length, 0 ), Type( static_cast<file_action>( dwRowFileAction ) ) //★
	/*文字列の長さとその文字列をとるwstringのコンストラクタを使っても同じ*/
{
	FileName.assign( Str, Length ); 
}
//メイン関数側
case WM_MODIFIED_FILE:
		switch (wParam) {
		case CURRENT_DIR_CODE: {
			const auto _ModifiedList = watcher::getChanged( CURRENT_DIR_CODE ); //★★
		}
		(後略)

アバター
へにっくす
記事: 625
登録日時: 6年前
住所: 東京都

Re: ReadDirectoryChangesWを別のスレッドで動かす

#2

投稿記事 by へにっくす » 1週間前

ええと、すみませんが

コード:

//メイン関数側
case WM_MODIFIED_FILE:
		switch (wParam) {
		case CURRENT_DIR_CODE: {
			const auto _ModifiedList = watcher::getChanged( CURRENT_DIR_CODE ); //★★
		}
ここのgetChanged関数の内容がないですね。
ただ言えることは、サブスレッド側で確保したメモリをメインスレッド側で参照しようとしているところが怪しい気はします。
written by へにっくす

きたぐに

Re: ReadDirectoryChangesWを別のスレッドで動かす

#3

投稿記事 by きたぐに » 1週間前

おはようございます。ミューテックスをロックしてその間に格納されているデータを回してあったら返す、というものになってます。

コード:

const std::vector<watcher::notify_info>& watcher::getChanged( const WPARAM& Code )
{
	std::lock_guard<std::mutex> _Lock( _get()._this );
	for (auto&& e : _get()._info) {
		if (e.Info.Code == Code) {
			return e.Info.Buffer;
		}
	}

	throw std::exception( "Unknown Code found" );
}
蛇足ですが

コード:

const std::vector<watcher::notify_info> watcher::getChanged( const WPARAM& Code )
{
	std::lock_guard<std::mutex> _Lock( _get()._this );
	for (auto&& e : _get()._info) {
		if (e.Info.Code == Code) {
			return e.Info.Buffer;
		}
	}

	throw std::exception( "Unknown Code found" );
}
のようにコピーを走らせると、
例外がスローされました:読み取りアクセス違反。
**_Pnext** が 0xFFFFFFFFFFFFFFFF でした。
呼び出し履歴によれば、文字列のデストラクタでなんかやらかしているので、間違っているのは確定ですね...

返信

“C言語何でも質問掲示板” へ戻る