spinlock (InterlockedExchange) vs. win32's CriticalSection for thread safety

In a current Windows program I am working on, there is an fstream object that represents a log file. it is contained in a wrapper class as a static variable so that multiple instances of the wrapper class may be instantiated, and all use the one fstream. The program is multi-threaded and most threads will have access to the log stream. When logging is enabled, all threads with access to the stream have the potential to write data to it, therefore, it is necessary to implement some kind of synchronization so that only one thread at a time will try to insert data into the fstream.
the two ways that I believe would be best is to either use a spin lock, or win32's CriticalSections. The spin lock is fastest, but may not be best, and the Critical Section requires that I call InitializeCriticalSection() and DeleteCriticalSection() which is annoying and makes me want to use a spinlock instead.
I would like to use one set of macros below around critical code, but I was wondering if anyone with experience in this area had a suggestion as to which would be better/more efficient for this scenario, or if another solution is best:

1
2
3
4
5
6
7
8
9
10
11
12
13
// these require InitializeCriticalSection()/DeleteCriticalSection() 
// which is annoying to implement within the wrapper class
// 'thread_safe' is just a bool that is true when InitializeCriticalSection() is
// called, and false when DeleteCriticalSection() is called
#define  ENTER_LFS_LOCK_   if( thread_safe ){ EnterCriticalSection( &c_s_ ); }
#define  EXIT_LFS_LOCK_    if( thread_safe ){ LeaveCriticalSection( &c_s_ ); }

/////////////////////////////////////////////////////////////////////////////////

// this is my preferred method, but i don't know if it is the better method
// lfsSpinLock is a 'long' and when it is '1' it is locked, and '0' is unlocked
#define  ENTER_LFS_LOCK_   while( InterlockedExchange( &lfsSpinLock, 1 ) == 1 ){ Sleep( 10 ); }
#define  EXIT_LFS_LOCK_    InterlockedExchange( &lfsSpinLock, 0 ); 


p.s. - I was also wondering, for setting/modifying regular 'int' variables using InterlockedExchange(), is it ok to use (long *) to cast it to a parameter that the function will accept since they are both 32 bits?
Last edited on
If you have an int*, then yes, you can cast it up to a long*...as a general rule you can always "upgrade" the type (i.e. int to double, long to long long, etc), and not have to worry about problems.

All I really used (when I used Windows Threads) was the Critical Sections...but I haven't really used them with wrapper classes...could you make the critical section a static variable and just check it each time?
thank you for your input, that is good to know that i can use those for ints. i could declare a static CRITICAL_SECTION structure, my problem with that, is that I plan on using this code for other projects. having a static critical section is ok, and I got it to work just fine with that, but then I also have to declare two methods to initialize/delete the critical section aside from entering and leaving each critical section. so then, when using the class, you have to make sure that you remember to call that member, and in a thread that is prior to any other threads that might try to use it. The idea is that using the simple spin lock, those two defines are literally all i need (as well as a variable declaration for the lock), and makes the class much much easier to use, no worrying about which instantiation will initialize the critical section first or anything like that. I just wasn't sure if the spin lock was a safe and viable way of doing this. again, thank you :)
Couldn't you just check the "thread_safe" variable, and then if it is, do it the way you did, and if it isn't, then initialize the section, then do the exact same thing?
Topic archived. No new replies allowed.