Obtaining a definition of compilation time other than that proposed by Nicholas Wilson will be extremely difficult, if not impossible, but assuming that the "background" really refers to functions, and not to multiple threads (I did not see any mention of threads in the question, so I assume that this is just a weird wording), you can trivially use the global flag and the locker, as well as assert or throw an exception. Or display a debug message. Of course, this will only be the lead time, but you must isolate the criminals very quickly. It will also have very little overhead for debugging collections (it is almost guaranteed to work from the L1 cache), but is not created for releases.
Using CaptureStackBackTrace , you must catch the address of the intruder function, which tool like addr2line (or any other MS equivalent) can be directly translated to a line in your code. There is probably even an instrumental help function that can directly execute this translation (although I don’t know).
So something like this (untested!) Might do the trick:
namespace global { int slow_flag = 0; } struct slow_func_locker { slow_func_locker() { ++global::slow_flag; } ~slow_func_locker(){ --global::slow_flag; } }; #indef NDEBUG #define REALTIME if(global::slow_flag) \ { \ void* backtrace; \ CaptureStackBackTrace(0, 1, &backtrace, 0); \ printf("RT function %s called from %08x\n", __FUNCTION__, backtrace); \ } #define SLOW_FUNC slow_func_locker slow_func_locker_; #else #define REALTIME #define SLOW_FUNC #endif foo_class::some_realtime_function(...) { REALTIME;
The only real drawback (besides compilation time) is that you should mark every slow and real function with any marker, but since the compiler cannot magically know what it is, there is no choice anyway.
Note that the global “flag” is indeed a counter, not a flag. The reason for this is that a slow function can immediately call another slow function that returns and clears the flag - incorrectly setting the fast function now (the critical section approach suggested by xgbi might be blocked in this case!). A counter prevents this. If you have threads, you can also replace int with std::atomic_int .
EDIT:
Since it is now clear that there really are 2 threads , and it matters only that one of them (the “fast” thread) never calls the “slow” function, there is another simple one (an example using the Win32 API, but can be executed with POSIX anyway):
When a “fast” stream starts (a “slow” stream should not do this), save the stream identifier somewhere, either as a global variable or as a member of an object that contains all the fast / slow functions — anywhere:
global::fast_thread_id = GetCurrentThreadId();
A macro to make "unwanted" function calls might look like this:
#define CHECK_FAST_THREAD assert(GetCurrentThreadID() != global::fast_thread_id)
This macro is then added to any “slow” function that should never be called from a “fast” thread. If the fast thread calls a function that it should not call, the assert triggers and it is known which function is called.