ホーム » VC OpenMP

VC OpenMP」カテゴリーアーカイブ

2024年4月
 123456
78910111213
14151617181920
21222324252627
282930  

カテゴリー

アーカイブ

ブログ統計情報

  • 79,631 アクセス



#pragma omp critical

共通のリソースに対してのコードを書いていて,ちょっと気になったので調べてみた.
テスト用に書いたのコードは次の様なもの.

#ifdef		_OPENMP
#include	<omp.h>
#endif

#include	<clocale>
#include	<iostream>

#ifdef	_MSC_VER
	#include	<tchar.h>
#else
	#define		 _T(x)			x
	typedef		char			TCHAR ;
#endif

#ifdef	_UNICODE
	#define		_tmain			wmain
	#define		tout			wcout
#else
	#define		_tmain			main
	#define		tout			cout
#endif

bool	test_n	(const long n)
{
	std::tout << _T("test_") << n << _T("\t") ;
	{
		for (long index=0 ; index<10 ; index++) {
			#ifdef	_OPENMP
			//	#pragma	omp	critical	//	(test)		//	--- (C)
			#endif
			{
				std::tout << (n*10 + index+1) << _T("\t") ;
				}
			}
		}
	return	true ;
	}

bool	test_	(void)
{
	std::tout << _T("test_") << std::endl ;
	{
		#ifdef	_OPENMP
			#pragma	omp	parallel for
		#endif
		for (long index=0 ; index<10 ; index++) {
			#ifdef	_OPENMP
				#pragma	omp	critical	//	(test)		//	--- (P)
			#endif
			{
				test_n(index) ;
				std::tout << std::endl ;
				}
			}
		}
	return	true ;
	}

int	_tmain	(int argc,TCHAR* argv[])
{
	{
		::test_() ;
		}
	return	0 ;
	}

実行させると,期待通り.
#pragma omp critical


ここで,関数 test_n() の次の行を有効にしてしまうと…
#pragma omp critical // (test) // — (C)
test_
test_0 致命的なユーザー エラー 1002: 同一名の 1 つで ‘#pragma omp critical’ が不適切に入れ子にされています
致命的なユーザー エラー 1002: 同一名の 1 つで '#pragma omp critical' が不適切に入れ子にされています
それぞれを異なる名称で指定する必要がある.
#pragma omp critical (test_n) // — (C)
#pragma omp critical (test_) // — (P)
#pragma omp critical 異なる名称
VC リリース版ではうまく動作してしまうこともある?


Linux 環境でコンパイルした a.out を NAS 環境に持っていくと,DS220+ では実行できた.
-fopenmp を付けたコンパイルは不可
TS253D では「libgomp.so がない」となって実行できない.
OpenMP  a.out の NAS での実行

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

OpenMP Fatal User Error 1002

OpenMP が有効な時でも動作する様にテストしていると…
Fatal User Error 1002: A ‘#pragma omp critical’ is illegally nested in one of the same name
Fatal User Error 1002: A '#pragma omp critical' is illegally nested in one of the same name
元々あった次のコードに #pragma omp critical としたことによるもの.

tstring	Get_Self_Original	(void)
{
	static	bool	Yet = true ;
	static	tstring	Self_original ;
	if (Yet) {
		tstring	self_name = ::Get_module_name() ;
		Self_original = Get_OriginalFilename(self_name.c_str()) ;
		if (Self_original.empty()) {
			Self_original = ::Path_GetName(self_name) ;
			}
		Yet = false ;
		}
	return	Self_original ;
	}

次の様に並列処理可能にすることで動作する様にはなるが …

tstring	Get_Self_Original	(void)
{
	#ifdef	_OPENMP
	//	#pragma	omp	critical	(_Get_Self_Original_)
	#endif
	{
	#ifdef	_OPENMP
			bool	Yet = true ;
			tstring	Self_original ;
	#else
		static	bool	Yet = true ;
		static	tstring	Self_original ;
	#endif
		if (Yet) {
			tstring	self_name = ::Get_module_name() ;
			Self_original = Get_OriginalFilename(self_name.c_str()) ;
			if (Self_original.empty()) {
				Self_original = ::Path_GetName(self_name) ;
				}
			Yet = false ;
			}
		return	Self_original ;
		}
	}

以前にも同じようなことをやっていた.
https://dev.mish.work/wordpress/2010/03/31/openmp-error-1002/


2023/04/27
この関数は exe の起動直後などに一度呼ばれることを意図しているので,critical をもっと局所的に.

tstring	Get_Self_Original	(void)
{
	static	bool	Yet = true ;
	static	tstring	Self_original ;
	if (Yet) {
		#ifdef	_OPENMP
			#pragma	omp	critical	(_Get_Self_Original_)
		#endif
		{
			tstring	self_name = ::Get_module_name() ;
			Self_original = Get_OriginalFilename(self_name.c_str()) ;
			if (Self_original.empty()) {
				Self_original = ::Path_GetName(self_name) ;
				}
			Yet = false ;
			}
		}
	return	Self_original ;
	}

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

CMutex の使用でデッドロック?

何年も前(2015/11?)からなのかもしれないが,
今の PC になってから作成した exe が起動時やサムネイルの表示などで停止する現象が時々発生している.
「ファイル更新監視」が停止
発生する頻度が低いのと,現象が絞り切れていなかったのでそのままになっていた.


今日,デバッグしていると exe が起動しない.
その時までに起動済みのものは動作しているが,止まってしまうものもあり.
以前この現象が発生した時は再起動することで回避したが,今回はもう少し調べてみることにした.


デバッガで追いかけると CMutex の Lock(INFINITE) で戻って来ない
CMutex Lock(INFINITE) で戻って来ない
使用している所は次の様な感じ.

{
	_MutexS_  mt(FALSE,_T("DocIB::GetBitmap")) ;
	MutexS    m(&mt) ;
	{
	//	共有のリソースに対する操作
		}
	}

通常の動作では Unlock されないことがある様には思えないが…
デバッガを使っていて Lock 中に exe を強制終了してしまったか?

_MutexS_	UseGdiPlus::ME(FALSE,_T("UseGdiPlus::GP_Token")) ;

{
	MutexS	me(&ME) ;
	if (IsInitialized())	{
		//	...
		}
	//	..
	}

いい修正方法が思い浮かばないので,とりあえずメモ.


2021/02/19
その後いろいろと検索して調べたが,通常の動作ではロックされたままとなることはなさそう.
https://docs.microsoft.com/ja-jp/dotnet/standard/threading/mutexes


表示されてはないが起動したままの exe があるかと思い,タスクバーを見たが特になさそう.
昨日,わかっているものの幾つかは「タスクの終了」で終わらせている.
そうなるとロックされている Mutex は,自前のシェルエクステンションと思われる.
「タスクバー」に表示されている「エクスプローラ」は終了させたが,まだ誰かがロックしている.
画面には表示されていない explorer.exe が幾つかか存在したので,すべて終わらせた.
これでロックされた Mutex は解放されたみたい.


今度は,デバッガを使用してうまく起動しなかった exe をいろいろ試すことに.
デバッガで Lock した直後にブレイクポイントを設定して停止.
当然であるが他の exe を起動すると Lock の所で止まってしまう.
デバッガで Unlock の後まで実行すると,他の exe も止まっていた所から動き出す.


デバッガで Lock した直後に停止させて,他の exe を起動.
デバッガで「デバッガの停止」してみる(Unlock していない)と,他の exe が動き出す.


これらの動作を見ると,使い方としてはそれ程間違ってはなさそう.
コードを追いかける限りでは,「マズい」所がわからない.
複数のプロセスから呼ばれた時に意図しないタイミングとなってしまう所があるのか?
ある程度はっきりしたのは,自前のシェルエクステンションの GDIPlus 関係の時の Lock で止まっていること.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

vcomp.dll が見つからないため、…

市販のアプリケーションやシェアウェアなどの利用の方は次のリンク先を参照してください.
https://mish.myds.me/wordpress/i-tools/2017/05/17/mfc140u-dll-error/
以下は開発者向けの情報です.


VC6 で作成したコンソール AP を VC7 以降に変換.
VC8 以降では OpenMP が使用できるので,コンパイルの設定を変更.
VC 8 OpenMP を有効にする設定
VC10 以降では問題ないが,VC8 ,VC9 でビルドしたものを実行すると,
—————————
gons_to.exe – システム エラー
—————————
vcomp.dll が見つからないため、コードの実行を続行できません。プログラムを再インストールすると、この問題が解決する可能性があります。
—————————
OK
—————————
vcomp.dll が見つからないため、コードの実行を続行できません。
—————————
gons_to.exe – システム エラー
—————————
VCOMP90.DLL が見つからないため、コードの実行を続行できません。プログラムを再インストールすると、この問題が解決する可能性があります。
—————————
OK
—————————
VCOMP90.DLL が見つからないため、コードの実行を続行できません。
しばらくわからなかったが,以前にも書いていた.
https://mish.myds.me/wordpress/dev/2013/03/14/vcompd-dll-debug-error/
main() 関数がある cpp に以下を追加.
 #ifdef _OPENMP
 #include <omp.h>
 #endif


omp.h を見ると lib や manifest の指定が書かれている.
omp.h の一部

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

ループ部分の OpenMP 対応

効果は低かったが,OpenMP を利用したコードに書きなおしてみた.


//---	オリジナルのコード  ----------------------------------------------------------------
	Ld2A	lins ;
	{
		for (size_t indexVV=0 ; indexVV<vv_plf.size() ; indexVV++) {
			v_PLF	v_plf = vv_plf[indexVV] ;
			if (v_plf.size() == 0)		{	continue ;		}
			for (size_t indexV=0 ; indexV<v_plf.size() ; indexV++) {
				PLF	plf = v_plf[indexV] ;
				if (plf.Is_line()) {
					Vd4A	v4a = plf ;
					Vd3A	v3a = ::ToVd3A(v4a) ;
					Vd2A	v2a = ::ToVd2A(v3a) ;
					for (size_t indexL=1 ; indexL<v2a.size() ; indexL++) {
						Vd2	s = v2a[indexL-1] ;
						Vd2	e = v2a[indexL-0] ;
						Ld2	lin(s,e) ;
						lins.push_back(lin) ;
						}
					}
				}
			}
		}
//----	OpenMP 対応 ------------------------------------------------------------------------
Ld2A	PLF_to_Ld2A	(const v_PLF& v_plf)
{
	Ld2A	lins ;
	{
		for (size_t indexV=0 ; indexV<v_plf.size() ; indexV++) {
			PLF	plf = v_plf[indexV] ;
			if (plf.Is_line()) {
				Vd4A	v4a = plf ;
				Vd3A	v3a = ::ToVd3A(v4a) ;
				Vd2A	v2a = ::ToVd2A(v3a) ;
				for (size_t indexL=1 ; indexL<v2a.size() ; indexL++) {
					Vd2	s = v2a[indexL-1] ;
					Vd2	e = v2a[indexL-0] ;
					Ld2	lin(s,e) ;
					lins.push_back(lin) ;
					}
				}
			}
		}
	return	lins ;
	}

Ld2A	PLF_to_Ld2A	(const vv_PLF& vv_plf)
{
	Ld2A	lins ;
	{
		#ifdef	_OPENMP
			#pragma	omp	parallel for
		#endif
		for (long indexVV=0 ; indexVV<long(vv_plf.size()) ; indexVV++) {
			v_PLF	v_plf = vv_plf[indexVV] ;
			if (v_plf.size() == 0)		{	continue ;		}
			Ld2A	ln_a = ::PLF_to_Ld2A(v_plf) ;
			#ifdef	_OPENMP
				#pragma	omp	critical	(PLF_to_Ld2A)
			#endif
			{
				lins.insert(lins.end(),ln_a.begin(),ln_a.end()) ;
				}
			}
		}
	return	lins ;
	}

ループ部分を並列化した実行結果

C:\Users\Iwao>C:\Temp\Test\Fill\GetX_1\ReleaseS.140\GetX_1.exe
31.856

C:\Users\Iwao>C:\Temp\Test\Fill\GetX_1\Release.140\GetX_1.exe
20.202

C:\Users\Iwao>

v_Vd2A	GetCross	(const vv_PLF& vv_plf,const Vd2& pt)
{
	Ld2A	lins = ::PLF_to_Ld2A(vv_plf) ;
	v_Vd2A	v_pnts ;
	{
		Vd2A	pnts ;
		pnts.push_back(pt) ;
		v_pnts.push_back(pnts) ;
		}
	{
		Ld2		lh(pt,pt+Vd2(1,0)) ; 
		Ld2		lv(pt,pt+Vd2(0,1)) ; 
		Vd2A	work_pnts ;
		#ifdef	_OPENMP
			#pragma	omp	parallel for
		#endif
		for (long index=0 ; index<long(lins.size()) ; index++) {
			Vd2	s = lins[index].S ;
			Vd2	e = lins[index].E ;
			Ed2	ext(s,e) ;
			Vd2	x ;
			if (get_cross_line(s,e,lh.S,lh.E,&x)) {
				if (::Is_point_in_extent(x,ext)) {
				//	pnts.push_back(x) ;
					}
				}
			if (get_cross_line(s,e,lv.S,lv.E,&x)) {
				if (::Is_point_in_extent(x,ext)) {
				//	pnts.push_back(x) ;
					}
				}
			{
				Vd2	h = ::get_near_on_line(s,e,pt) ;
				if (::Is_point_in_extent(h,ext)) {
					#ifdef	_OPENMP
						#pragma	omp	critical	(GetCross)
					#endif
					{
						work_pnts.push_back(h) ;
						if (work_pnts.size() > 10) {
							v_pnts.push_back(work_pnts) ;
							work_pnts.clear() ;
							}
						}
					}
				}
			}
		v_pnts.push_back(work_pnts) ;
		}
	return	v_pnts ;
	}

ループ部分の OpenMP 対応

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

実行時のエラー OpenMP

普段通っているコードなのに,ある条件(操作)で実行時にエラー.
エラーの場所はある範囲(DelFileE への登録)ではあるが,固定されてない.
 CStringArray に CString の追加.
コールスタックを見ると MakeFace$omp$1 とある.


   ucrtbased.dll!__VCrtDbgReportA () 不明
   ucrtbased.dll!__CrtDbgReport () 不明
   mfc140ud.dll!AfxAssertFailedLine(const char * lpszFileName, int nLine) 行 333 C++
   mfc140ud.dll!CWnd::DestroyWindow() 行 1055 C++
   mfc140ud.dll!CToolTipCtrl::DestroyToolTipCtrl() 行 73 C++
   mfc140ud.dll!AFX_MODULE_THREAD_STATE::~AFX_MODULE_THREAD_STATE() 行 253 C++
   mfc140ud.dll!AFX_MODULE_THREAD_STATE::`scalar deleting destructor'(unsigned int) C++
   mfc140ud.dll!CThreadSlotData::DeleteValues(CThreadData * pData, HINSTANCE__ * hInst) 行 354 C++
   mfc140ud.dll!CThreadSlotData::DeleteValues(HINSTANCE__ * hInst, int bAll) 行 396 C++
   mfc140ud.dll!AfxTermLocalData(HINSTANCE__ * hInst, int bAll) 行 494 C++
   mfc140ud.dll!DllMain(HINSTANCE__ * hInstance, unsigned long dwReason, void * __formal) 行 663 C++
   mfc140ud.dll!dllmain_dispatch(HINSTANCE__ * const …, void * const reserved) 行 195 C++
   mfc140ud.dll!_DllMainCRTStartup(HINSTANCE__ * const …, void * const reserved) 行 248 C++
   ntdll.dll!_LdrpCallInitRoutine@16 () 不明
   ntdll.dll!_LdrShutdownProcess@0 () 不明
   ntdll.dll!_RtlExitUserProcess@4 () 不明
   kernel32.dll!_ExitProcessStub@4 () 不明
   ucrtbased.dll!__crt_hmodule_traits::close(struct HINSTANCE__ *) 不明
   ucrtbased.dll!__crt_hmodule_traits::close(struct HINSTANCE__ *) 不明
   ucrtbased.dll!__Exit () 不明
   ucrtbased.dll!_raise () 不明
   ucrtbased.dll!__acrt_lock_and_call<class <lambda_fe…55> >(enum __acrt_lock_id,class <…; &&) 不明
   ucrtbased.dll!___acrt_MessageWindowA () 不明
   ucrtbased.dll!__VCrtDbgReportA () 不明
   ucrtbased.dll!__CrtDbgReport () 不明
   mfc140ud.dll!AfxAssertFailedLine(const char * lpszFileName, int nLine) 行 333 C++
   mfc140ud.dll!CStringArray::SetSize(int nNewSize, int nGrowBy) 行 165 C++
   mfc140ud.dll!CStringArray::SetAtGrow(int …, const ATL::CStringT<wchar_t,… > & newElement) 行 265 C++
   mfc140ud.dll!CStringArray::Add(const ATL::CStringT<wchar_t, … > & newElement) 行 322 C++
   BlockIn.exe!DelFileE::Add(const wchar_t * fileName) 行 51 C++
   BlockIn.exe!CacheFile::GetCF_Name(const wchar_t * srcName, const unsigned int dibWidth) 行 415 C++
   BlockIn.exe!PartsA_To::ToIPX(const wchar_t * ipxName) 行 257 C++
   BlockIn.exe!PartsA_To::DumpDebug(const int delFE, const wchar_t * pre_) 行 297 C++
   BlockIn.exe!PartsA_To::DumpDebug(const wchar_t * pre) 行 47 C++
   BlockIn.exe!PartsA_Fnc_DebugDump(PartsA & partsAry, const wchar_t * pre) 行 818 C++
   BlockIn.exe!MaPat__DebugDump(const Parts & parts) 行 3293 C++
   BlockIn.exe!MaPat::MakePartsFace(const int makeEdge) 行 3481 C++
   BlockIn.exe!BAPat::MakePartsFace(const int makeEdge) 行 1508 C++
   BlockIn.exe!BAPat::GetPartsFace(const int makeEdge) 行 1935 C++
   BlockIn.exe!BlockInf::MakeFace(const int makeEdge) 行 3465 C++
> BlockIn.exe!BlockLay::MakeFace$omp$1() 行 4320 C++
   [外部コード]


次の様に #pragma omp critical を追加.
  BOOL DelFileE::Add (LPCTSTR fileName)
  {
     #ifdef _OPENMP
       #pragma omp critical (DelFileE_Add)
     #endif
     {
       CString filePath = ::FolderDelLastSP(fileName) ;
       DelFileName.Add(filePath) ;
       }
     return TRUE ;
     }

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

MessageBar クラスと OpenMP

新しい Message クラスを使用して,OpenMP 対応の動作のテスト.
void CTSttBView::OnTestDrawBar2()
{
  Message tmp ;
  ElapseTick et ;
  #define BAR_COUNT_2 1000000
  #ifdef _OPENMP
    #pragma omp parallel for
  #endif
  for (int i=0 ; i<100 ; i++) {
    Message bar ;
    bar.SetBar (_T(“Test Message 1 M * 100”),BAR_COUNT_2,RGB(0,255,0)) ;
    for (int index=0 ; index<BAR_COUNT_2 ; index++) {
      bar.SetBarInc() ;
      }
    }
  DWORD elapseT = et.GetElapse() ;
  CString str ; str.Format(_T(“%.2f 秒”),elapseT/1000.) ;
  AfxMessageBox(str) ;
  }
1 億回 SetBarInc を呼出していて,10 秒程度だったのが,#pragma omp parallel for で 20 秒程度になってしまった.


inline bool MessageBase::SetBarInc (void)
{
  if (GetBarMax() == 0) { return false ; }
  if (GetBarCount() < GetBarMax()) { B_Counter++ ; }
  else { B_Counter = 0 ; } // reset
  IncCounterR() ;
  {
    long lastPos = long(100*(GetBarCount()-1)/GetBarMax()) ;
    long new_Pos = long(100*(GetBarCount()-0)/GetBarMax()) ;
    if (lastPos == new_Pos) { return true ; }
    }
  #ifdef _WINDOWS
  #ifdef _MFC_VER
  #ifdef _OPENMP
    if (AfxGetMainWnd() == NULL) { return false ; }
  #endif
  #endif
  #endif
  return SetBarCount(B_Counter) ;
  }
AfxGetMainWnd() を呼出す回数を減らすことにより,3 秒程度に.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

~iDocText でダウン

先日作成した TextureToPath 関係でダウンする様になってしまった.
場所は,iDocText のデストラクタ付近.
呼出し元をたどると,#pragma omp parallel for .


TextureCopy::GetDrawName に #pragma omp critical (TextureCopy_GetDrawName) を追加.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

vcompd.dll が見つからなかったため …

VC 8 で FBXtoPA を OpenMP に変更してビルド,実行すると
—————————
FBXtoPA.exe – コンポーネントが見つかりません
—————————
vcompd.dll が見つからなかったため、このアプリケーションを開始できませんでした。
アプリケーションをインストールし直すとこの問題は解決される場合があります。
—————————
OK
—————————
OpenMP debug error
検索すると,omp.h のインクルードがないための現象.
アプリケーションクラスのソースに,以下を追加して OK .
  #ifdef _OPENMP
  #include <omp.h>
  #endif

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

OpenMP AfxGetMainWnd

ワーカースレッドからの AfxGetMainWnd の呼出しでは,NULL になる?
メインスレッドは正しく取得できる.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

OpenMP エラー 1002

—————————
致命的なユーザー エラー 1002:
—————————
同一名の 1 つで ‘#pragma omp critical’ が不適切に入れ子にされています
致命的なユーザー エラー 1002: 同一名の 1 つで ‘#pragma omp critical’ が不適切に入れ子にされています
2.9 ディレクティブの入れ子
局所的になる様に,呼び出し元での “#pragma omp critical” を削除.

class Profile {
  ...
protected:
  LPCTSTR  LastProfileName ;
  CString  C_T_ProfileName ;
  ...
  } ;

BOOL Profile::SaveProfileName(void)
{
  CWinApp* app = AfxGetApp() ;
  if (app== NULL) { return FALSE ; }
  LastProfileName = AfxGetApp()->m_pszProfileName ;
  AfxGetApp()->m_pszProfileName = C_T_ProfileName ;
  return TRUE ;
  }
BOOL Profile::LoadProfileName(void)
{
  AfxGetApp()->m_pszProfileName = LastProfileName ;
  return TRUE ;
  }

omp critical ではなく,MFC 同期クラスを使用する様に変更.

//  以下は,テスト用のコード
BOOL Profile::?et??? (LPCTSTR lpszSection,LPCTSTR lpszEntry,...)
{
  ...
  CMutex m(FALSE,MN_LPN) ;
  m.Lock() ;
// return    ???Profile??? (lpszSection, lpszEntry, ...) ;
  BOOL ret = ???Profile??? (lpszSection, lpszEntry, ...) ;
  m.Unlock() ;
  return ret ;
  }
//  MFC 同期クラスの呼出しはコストがかからない様に修正する
Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

OpenMP プロジェクトの設定

VC8 以降 プロジェクトのプロパティページ
「構成プロパティ」-「C/C++」-「言語」-「OpenMP サポート」を「はい」に設定.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.