C++ Standards, Extensions, and Interop


Problem with _controlfp and thread context (OpenMP)


Hello,
I try to used the function _controlfp() in a multi thread context (especially OpenMP), and it seems that this function doesn't work in multi thread context.
It happens, that fp status isn't change for all threads.
Here a example to reproduce the problem:
// ControlFP_OpenMP.cpp : Defines the entry point for the console application.
//
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <omp.h>
#include <mutex>
class ScopeFPEDisabler
{
static std::mutex ms_Mutex;
static int ScopeFPEDisablerCounter;
public:
ScopeFPEDisabler()
{
std::unique_lock<std::mutex> lock(ms_Mutex);
if(ScopeFPEDisablerCounter == 0)
{
// Clear any pending FP exceptions
_clearfp();
// Suppress the FP exceptions
_controlfp(_MCW_EM, _MCW_EM);
}
++ScopeFPEDisablerCounter;
}
~ScopeFPEDisabler()
{
// Decrement the counter and test if it is the last RshFPEDisabler
std::unique_lock<std::mutex> lock(ms_Mutex);
--ScopeFPEDisablerCounter;
if(ScopeFPEDisablerCounter == 0)
{
// Clear any pending FP exceptions
_clearfp();
// Restore the FP exceptions status
_controlfp(_EM_UNDERFLOW | _EM_DENORMAL | _EM_INEXACT, _MCW_EM);
}
}
};
std::mutex ScopeFPEDisabler::ms_Mutex;
int ScopeFPEDisabler::ScopeFPEDisablerCounter = 0;
//--------------------
//
int main(int argc, char* argv[])
{
_controlfp(_EM_UNDERFLOW | _EM_DENORMAL | _EM_INEXACT, _MCW_EM);
unsigned int savedFPEStatus = _controlfp(0, 0);
for(unsigned int loopIdx = 0; loopIdx < 10; ++loopIdx)
{
#pragma omp parallel
{
try
{
ScopeFPEDisabler disableFPE;
float smallValue = 1.e-25f;
float bigValue = 1.e25f;
float result = smallValue + bigValue;
float div = result;
if(result < 0)
div = 10.f;
div -= result;
result += result;
result = result / div;
}
catch(...)
{
printf("Exception !\n");
}
}
printf("savedFPEStatus: 0x%x, current status: 0x%x\n", savedFPEStatus, _controlfp(0, 0));
}
return 0;
}
Enable "OpenMP support" and "Exception with SEH exceptions" in project options to see the problem.
The result of the execution of this code on a 4 core processor (Core i7, 8 threads) is:
savedFPEStatus: 0x90003, current status: 0x90003
Exception !
Exception !
Exception !
Exception !
Exception !
Exception !
savedFPEStatus: 0x90003, current status: 0x9001f
Exception !
Exception !
Exception !
Exception !
Exception !
Has you can see, controlfp() don't change the status on processor for each thread. On some OpenMP thread, the status is bad, and sometimes, the status isn't reset correctly.
If the object ScopeFPEDisabler is move outside of the OpenMP section, it works.
My question is: why doesn't it not work ? How to solve the problem ?
Moving the function _controlfp() outside of the OpenMP section isn't really a solution in my context, while sometime it's not easy to know is a function is call in a muti threaded context or not.
Remark: why I enable/disable FPE ? because some parts of code must not launch exception if there is floating point exception (third party library), while my own code must launch exception when there is floating point exception.
best regards,
François.
"it could sometimes also affect other threads."
The only way that could happen is that there's a nasty bug in the kernel (or perhaps in a driver). Unlikely.
_controlfp simply sets the x87 and SSE control registers, FCW and MXCSR. Like most of CPU registers these 2 are part of the thread context and any change made to them will affect only the current thread.
If you remove the ScopeFPEDisableCounter machinery you'll see that the code works fine, at least it does on my machine. If you really want to use the counter then you have to make it thread static.
Seems that _controlfp has effect on current thread only:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/b17f4f7d-6ef9-4d9f-8b87-bceaf37d0362. Try an experiment:
_controlfp( ~_EM_ZERODIVIDE,
_EM_ZERODIVIDE );
printf( "Main thread: %i, Control Word: %X\n",
GetCurrentThreadId(), _controlfp( 0,
0 ) );
#pragma omp parallel
num_threads(2)
{
printf( "Thread: %i, Control Word: %X\n",
GetCurrentThreadId(), _controlfp( 0,
0 ) );
}
printf( "------------\n" );
_controlfp( _EM_ZERODIVIDE,
_EM_ZERODIVIDE );
printf( "Main thread: %i, Control Word: %X\n",
GetCurrentThreadId(), _controlfp( 0,
0 ) );
#pragma omp parallel
num_threads(2)
{
printf( "Thread: %i, Control Word: %X\n",
GetCurrentThreadId(), _controlfp( 0,
0 ) );
}
Therefore you have to set the control word inside each thread.
By the way, in order to parallelise a loop, consider ‘#pragma omp parallel for’.
 Hi Viorel,
it could sometimes also affect other threads. If your replace num_threads(2) by num_threads(8), you will see that some threads will have the good value.
In any case, it seems that the correction is to set the flag on each thread to be sure of the result.
For the directive "#pragma omp parallel for" , I don't use it, because
there is no way to catch exception when you use it.
best regards,
François.
"it could sometimes also affect other threads."
The only way that could happen is that there's a nasty bug in the kernel (or perhaps in a driver). Unlikely.
_controlfp simply sets the x87 and SSE control registers, FCW and MXCSR. Like most of CPU registers these 2 are part of the thread context and any change made to them will affect only the current thread.
If you remove the ScopeFPEDisableCounter machinery you'll see that the code works fine, at least it does on my machine. If you really want to use the counter then you have to make it thread static.

Related Links

int i = 2; Is this the Assingment Operator here ?
How do you define a template class's constructor outside the class
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function ___tmainCRTStartup
How to use another variable from another Form in VisualC++
Accessing a member through a pointer
How to copy one char* array into another one?
definition of dllimport static data member not allowed
LockFile problem
mspdbsrv.exe consuming over 1.4GB
Visual c++, how to find a file in certain folder and print its name?
abstract classes in cpp
Convert float to String
LNK1104 error - DEBUG vs. RELEASE
recvfrom on a udp socket does not receive in release build/mode
Error C2039, error c2065 with compiler setting at /clr
Is there any GDI function which can return the local name of a font?

Categories

MSDN
Microsoft Office for D...
Microsoft Azure
.NET Framework
Data Platform Development
Data Platform Developm...
Microsoft Sync Framework
Feedback and Discussions
Windows Phone Preview ...
Microsoft R
Software Entwicklung f...
Parallel Computing in ...
Windows App Studio Beta
Windows Desktop Develo...
Application Security f...
Windows Desktop Pro-Au...
Windows Desktop SDK
General Office Develop...
Excel for Developers
Office 365 for Developers
SharePoint 2010 - Gene...
SharePoint Legacy Vers...
Azure App Service - We...
Azure Backup
Azure Cache
Machine Learning
StorSimple
Azure Data Catalog
Azure Log Integration
Azure Time Series Insi...
.NET Framework Class L...
Team Foundation Server...
Visual FoxPro General
Commerce Server 2007
Microsoft Solver Found...
Debugger Canvas
Scripting
SyncFx - SyncToy-File ...
Windows Mobile Develop...
Visual Studio Smart De...
SQL Server Reporting S...
SQL Server Data Access
SQL Server SMO/DMO
SQL Server High Availa...
Microsoft Drivers for ...
SQL Server Search
SQL Server Spatial
SQL Server Data Qualit...
Standard 2009: Compone...
Standard 2009: Tools
Standard 7: Misc
Windows Forms Designer
Live Connect (Archived)
Windows Live Messenger...
MSDN Subscriptions Fee...
WebsitePanel - Develop...
Known Issues for Windo...
Exchange Server Develo...
Microsoft Lync Client ...
Report a Silverlight Bug
Silverlight Video and ...
Expression Design
Microsoft Online Syndi...
Visual Studio Report C...
Retired SharePoint Soc...
.NET StockTrader Sampl...
Acropolis
Archived: Software Tes...
Axum Incubation Project
Building Windows Store...
CAT.NET
Direct3D 10
Game Technologies: Aud...
General Troubleshootin...
ISV Community Days
JScript for the .NET F...
Microsoft Security Dev...
Microsoft Unified Comm...
Office Live Small Busi...
patterns & practices: ...
Pex and Moles PowerTool
Popfly Explorer
Search Server: Frequen...
Share your How to samp...
SQL Server 2014 Setup ...
TFS Deployment to Azure
Visual Basic 2008 (Pre...
Visual Basic for Appli...
Visual Basic Language
Visual C# Language
Visual Studio Editor i...
Visual Studio Gallery ...
Visual Studio Team Sys...
WCF Data Services (Pre...
Web Development in Vis...
Windows Developer Prev...
Windows Live Data Deve...
Windows Phone push not...
XML in Visual Studio 2...

Resources

Encrypt Message



code
soft
python
ios
c
html
jquery
cloud
mobile