// intrinExample.cpp
// compile with: /EHsc /O2
// Simple example of using _Interlocked* intrinsics to
// do manual synchronization
//
// Add [-DSKIP_LOCKING] to the command line to disable
// the locking. This will cause the threads to execute out
// of sequence.
#include "windows.h"
#include <iostream>
#include <queue>
#include <intrin.h>
using namespace std;
// --------------------------------------------------------------------
// if defined, will not do any locking on shared data
//#define SKIP_LOCKING
// A common way of locking using _InterlockedCompareExchange.
// Please refer to other sources for a discussion of the many issues
// involved. For example, this particular locking scheme performs well
// when lock contention is low, as the while loop overhead is small and
// locks are acquired very quickly, but degrades as many callers want
// the lock and most threads are doing a lot of interlocked spinning.
// There are also no guarantees that a caller will ever acquire the
// lock.
namespace MyInterlockedIntrinsicLock
{
typedef unsigned LOCK, *PLOCK;
#pragma intrinsic(_InterlockedCompareExchange, _InterlockedExchange)
enum {LOCK_IS_FREE = 0, LOCK_IS_TAKEN = 1};
void Lock(PLOCK pl)
{
#if !defined(SKIP_LOCKING)
// If *pl == LOCK_IS_FREE, it is set to LOCK_IS_TAKEN
// atomically, so only 1 caller gets the lock.
// If *pl == LOCK_IS_TAKEN,
// the result is LOCK_IS_TAKEN, and the while loop keeps spinning.
while (_InterlockedCompareExchange((long *)pl,
LOCK_IS_TAKEN, // exchange
LOCK_IS_FREE) // comparand
== LOCK_IS_TAKEN)
{
// spin!
// call __yield() here on the IPF architecture to improve
// performance.
}
// This will also work.
//while (_InterlockedExchange(pl, LOCK_IS_TAKEN) ==
// LOCK_IS_TAKEN)
//{
// // spin!
//}
// At this point, the lock is acquired.
#endif
}
void Unlock(PLOCK pl) {
#if !defined(SKIP_LOCKING)
_InterlockedExchange((long *)pl, LOCK_IS_FREE);
#endif
}
}
// ------------------------------------------------------------------
// Data shared by threads
queue<int> SharedQueue;
MyInterlockedIntrinsicLock::LOCK SharedLock;
int TicketNumber;
// ------------------------------------------------------------------
DWORD WINAPI
ProducerThread(
LPVOID unused
)
{
while (1) {
// Acquire shared data. Enter critical section.
MyInterlockedIntrinsicLock::Lock(&SharedLock);
//cout << ">" << TicketNumber << endl;
SharedQueue.push(TicketNumber++);
// Release shared data. Leave critical section.
MyInterlockedIntrinsicLock::Unlock(&SharedLock);
Sleep(rand() % 20);
}
return 0;
}
DWORD WINAPI
ConsumerThread(
LPVOID unused
)
{
while (1) {
// Acquire shared data. Enter critical section
MyInterlockedIntrinsicLock::Lock(&SharedLock);
if (!SharedQueue.empty()) {
int x = SharedQueue.front();
cout << "<" << x << endl;
SharedQueue.pop();
}
// Release shared data. Leave critical section
MyInterlockedIntrinsicLock::Unlock(&SharedLock);
Sleep(rand()%20);
}
return 0;
}
int main(
void
)
{
const int timeoutTime = 500;
int unused1, unused2;
HANDLE threads[4];
// The program creates 4 threads:
// two producer threads adding to the queue
// and two consumers taking data out and printing it.
threads[0] = CreateThread(NULL,
0,
ProducerThread,
&unused1,
0,
(LPDWORD)&unused2);
threads[1] = CreateThread(NULL,
0,
ConsumerThread,
&unused1,
0,
(LPDWORD)&unused2);
threads[2] = CreateThread(NULL,
0,
ProducerThread,
&unused1,
0,
(LPDWORD)&unused2);
threads[3] = CreateThread(NULL,
0,
ConsumerThread,
&unused1,
0,
(LPDWORD)&unused2);
WaitForMultipleObjects(4, threads, TRUE, timeoutTime);
return 0;
}
Output
<0 <1 <2 <3 <4 <5 <6 <7 <8 <9 <10 <11 <12 <13 <14 <15 <16 <17 <18 <19 <20 <21 <22 <23 <24 <25 <26 <27 <28 <29
END Microsoft Specific
本文通过一个简单的示例展示了如何使用_Intrin锁来实现多线程环境下的手动同步,包括生产者和消费者模式的数据共享过程。
926

被折叠的 条评论
为什么被折叠?



