int SafeFloatDivide_pred(float a, float b, float d)
{
// convert Boolean (b != 0.0f) into either 1U or 0U
const unsigned condition = (unsigned)(b != 0.0f);
// convert 1U -> 0xFFFFFFFFU
// convert 0U -> 0x00000000U
const unsigned mask = 0U - condition;
// calculate quotient (will be QNaN if b == 0.0f)
const float q = a / b;
// select quotient when mask is all ones, or default
// value d when mask is all zeros (NOTE: this won't
// work as written -- you'd need to use a union to
// interpret the floats as unsigned for masking)
const float result = (q & mask) | (d & ~mask);
return result;
}
This technique for selecting one of two possible values is called predication or a select operation
Queue g_queue;
sem_t g_semUsed; // initialized to 0
sem_t g_semFree; // initialized to 1
void* ProducerThreadSem(void*)
{
// keep on producing forever...
while (true)
{
// produce an item (can be done non-
// atomically because it's local data)
Item item = ProduceItem();
// decrement the free count
// (wait until there's room)
sem_wait(&g_semFree);
AddItemToQueue(&g_queue, item);
// increment the used count
// (notify consumer that there's data)
sem_post(&g_semUsed);
}
return nullptr;
}
void* ConsumerThreadSem(void*)
{
// keep on consuming forever...
while (true)
{
// decrement the used count
// (wait for the data to be ready)
sem_wait(&g_semUsed);
Item item = RemoveItemFromQueue(&g_queue);
// increment the free count
// (notify producer that there's room)
sem_post(&g_semFree);
// consume the item (can be done non-
// atomically because it's local data)
ConsumeItem(item);
}
return nullptr;
}
std::atomic<float> g_data;
std::atomic_flag g_ready = false;
void ProducerThread()
{
// produce some data
g_data = 42;
// inform the consumer
g_ready = true;
}
void ConsumerThread()
{
// wait for the data to be ready
while (!g_ready)
PAUSE();
// consume the data
ASSERT(g_data == 42);
}
class UnnecessaryLock
{
volatile bool m_locked;
public:
void Acquire()
{
// assert no one already has the lock
assert(!m_locked);
// now lock (so we can detect overlapping
// critical operations if they happen)
m_locked = true;
}
void Release()
{
// assert correct usage (that Release()
// is only called after Acquire())
assert(m_locked);
// unlock
m_locked = false;
}
};
#if ASSERTIONS_ENABLED
#define BEGIN_ASSERT_LOCK_NOT_NECESSARY(L) (L).Acquire()
#define END_ASSERT_LOCK_NOT_NECESSARY(L) (L).Release()
#else
#define BEGIN_ASSERT_LOCK_NOT_NECESSARY(L)
#define END_ASSERT_LOCK_NOT_NECESSARY(L)
#endif
// Example usage...
UnnecessaryLock g_lock;
void EveryCriticalOperation()
{
BEGIN_ASSERT_LOCK_NOT_NECESSARY(g_lock);
printf("perform critical op...\n");
END_ASSERT_LOCK_NOT_NECESSARY(g_lock);
}