在 Visual Studio 的情况下,声明为 volatile 的变量将包括内存栅栏操作(除非此选项被关闭,否则默认情况下它是打开的),允许它们在线程之间使用。鉴于此,代码可以使用 volatile 变量来播放音乐曲目。我在下面包含了示例 C 代码。
我假设在播放音乐时,Beep() 不会受 cpu 限制(它似乎不适用于 Windows XP)。
为了更准确的计时,timeBeginPeriod() 可用于将时钟频率从 64hz (15.625 ms) 增加到 1000hz (1 ms)。在 Windows XP 和 Windows 2000 的情况下,timeBeginPeriod(1) 导致代码实际以 1024hz 运行,而 Sleep() 和我的猜测 Beep() 通过每 128 个滴答声添加 3 个额外的实际滴答声来模拟 1000hz 代码。在 125 毫秒的边界上。这意味着 Sleep(1) 可能偶尔会花费近 2 毫秒(在 42、84 和 125 调用中)。
注意 - 最终由于缺少可与之通信的硬件,Windows Vista 和 Windows XP 64 位版本中不再支持 Beep。在 Windows 7 中,Beep 被重写以将哔声传递给会话的默认声音设备。这通常是声卡,除非在终端服务下运行,在这种情况下会在客户端上呈现哔声。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679277(v=vs.85).aspx
多线程“哔”代码示例。此代码使用 PC 扬声器在 Windows XP 上按预期工作。在 Windows 7 上,它使用声卡,并且音符之间有一些静音。
/*----------------------------------------------------------------------*/
/* mtbeep.c multi-thread beep demo */
/*----------------------------------------------------------------------*/
#include <windows.h>
/* include winmm.lib for timeBeginPeriod */
#pragma comment(lib, "winmm.lib")
#define TRACK0 0
#define TRACK1 1
#define TRACK2 2
#define TRACKX 3 /* exit thread 1 if trackx */
typedef struct {
DWORD dwFreq;
DWORD dwDuration;
}NOTE;
/*----------------------------------------------------------------------*/
/* data */
/*----------------------------------------------------------------------*/
static HANDLE htT1; /* thread 1 handle */
static DWORD dwThreadT1; /* thread id's (not used) */
static volatile DWORD dwTrack; /* beep track to play */
/* songs */
static NOTE anTrack0[4] = {300, 500, 450, 500, 600, 500, 0, 0};
static NOTE anTrack1[4] = { 0, 250};
static NOTE anTrack2[4] = {400, 500, 300, 500, 200, 500, 0, 0};
static NOTE anTrackx[4] = {0, 0};
/*----------------------------------------------------------------------*/
/* code */
/*----------------------------------------------------------------------*/
static DWORD WINAPI Thread0(LPVOID);
static DWORD WINAPI Thread1(LPVOID);
/*----------------------------------------------------------------------*/
/* main */
/*----------------------------------------------------------------------*/
DWORD main(DWORD argc, BYTE **argv)
{
timeBeginPeriod(1); /* set period to 1ms */
Sleep(128); /* wait for it to stabilize */
/* create thread */
htT1 = CreateThread(NULL, 0, Thread1, 0, 0, &dwThreadT1);
if(!htT1){
/* createthread failed */
goto exit0;}
Thread0((LPVOID)NULL); /* start Thread 0 */
exit0:
if(htT1){ /* close thread */
dwTrack = TRACKX;
WaitForSingleObject(htT1, INFINITE);
CloseHandle(htT1);}
timeEndPeriod(1); /* restore period */
return(0);
}
/*----------------------------------------------------------------------*/
/* Thread0 */
/*----------------------------------------------------------------------*/
static DWORD WINAPI Thread0(LPVOID lpvoid)
{
int i;
for(i = 0; i < 4; i++){
dwTrack = i%3;
Sleep(5000);
}
return 0;
}
/*----------------------------------------------------------------------*/
/* Thread1 beep thread */
/*----------------------------------------------------------------------*/
static DWORD WINAPI Thread1(LPVOID lpvoid)
{
NOTE *apTrack[4] = {anTrack0, anTrack1, anTrack2, anTrackx};
NOTE *pTrack = anTrack0; /* ptr to array of notes */
DWORD cTrack = TRACKX; /* current track */
int iNote = 0; /* note index */
while(dwTrack != TRACKX){ /* play a note loop */
if(cTrack != dwTrack){ /* if song changed */
iNote = 0; /* start at first note */
cTrack = dwTrack; /* of next song */
pTrack = apTrack[cTrack];
}
if(!pTrack[iNote].dwDuration) /* if end of song */
iNote = 0; /* reset note index */
if(pTrack[iNote].dwFreq) /* if note play it */
Beep(pTrack[iNote].dwFreq, pTrack[iNote].dwDuration);
else /* else silence */
Sleep(pTrack[iNote].dwDuration);
iNote++;
}
return(0);
}