C++中的异步线程

问题描述:

我们使用Visual Studio 2005开发游戏(我们的一些计算机仍然运行Windows 2000,这是最新版本,我们无法轻易将其转换为新版本) 。C++中的异步线程

我们的音乐作曲家已经写了一些短小的曲目来测试系统已经出现,但问题已经出现: 游戏在播放音乐或音效时冻结。

虽然这对SFX来说并不是什么大问题,但音乐是一个非常大的问题,因为我们需要它在后台运行。

我想我们大概可以在后台创建第二个线程或进程来在循环中播放指定的轨道,但是当我搜索时我找不到任何可用于此的任何内容,因为需要有数据转移(尽管是单向)两个过程之间。

我看到它的方式,我们应该能够从包含音轨编号的主程序向音乐进程传递命令 - 这应该是相当简单的,但我们最近已转移到C++,目前非常有经验。

感谢您的任何建议。

P.S.请不要评论我们使用过时的软件,我们这样做是为了好玩,并且不打算投入任何资金。

编辑:为了清楚起见,如果不清楚,我们都在运行Windows,并不打算将其移植到任何其他平台 - 我们正在运行Visual Studio 2005,但计划将开始移动到Visual Studio 2008或2010 Ultimate,一旦我们可以获得适当的光盘和软件。

音乐完全不使用Beep();命令内置到标准的Windows头文件(windows.h)中。

我们想运行一个与主程序平行的辅助进程来允许背景音乐。

如果事实证明两个进程之间的数据传输过于严酷,我们能否在启动时将启动变量传递给它作为音轨编号,并在完成时简单地将其杀死?

+0

有描述WIN32的[多线程]上MSDN资源(https://msdn.microsoft.com/en-us/library/y6h8hye8(V = VS.80)的.aspx)的能力。如果不能访问更新的C++特性,比如''库,那么最终你不得不使用WIN32系统调用手动完成大量的C++功能。 – lcs

+0

如果您只传输一个音轨编号,只需使用一些atomic int'trackNum'var,并让音效线程在它到达音轨末尾时读取它,并且需要选择一个音轨编号(或重复相同的一个)。如果你需要阻止它,你可以安排'-1'来表示'停止播放并且现在等待一个事件'。 – ThingyWotsit

+0

是的,但我们将如何创建新线程并允许此?你能举一个简单的例子吗? – FAMICOMASTER

在Visual Studio的情况下,声明为volatile的变量将包含内存fence操作(除非此选项被关闭,默认情况下它是打开的),允许它们在线程之间使用。鉴于此,代码可以使用音乐曲目播放的易变变量。我在下面包含了示例C代码。

我假设在播放音乐时,Beep()不会被CPU绑定(它似乎不适用于Windows XP)。

为了更准确的计时,可以使用timeBeginPeriod()将报警频率从64hz(15.625 ms)增加到1000hz(1 ms)。在Windows XP和Windows 2000的情况下,timeBeginPeriod(1)使得ticker实际运行在1024hz,而Sleep()和我的猜测Beep()通过在每128个ticks添加3个额外的实际ticks来模拟1000hz ticker结束在125毫秒的边界上。这意味着Sleep(1)可能偶尔需要将近2ms(在42,84和125次调用中)。

注 - 最终由于缺乏与硬件进行通信,在Windows Vista和Windows XP 64位版本中,对哔声的支持被丢弃。在Windows 7中,重写了哔声以将哔声传递给会话的默认声音设备。这通常是声卡,除非在终端服务下运行,在这种情况下,客户端上会发出嘟嘟声。

https://msdn.microsoft.com/en-us/library/windows/desktop/ms679277(v=vs.85).aspx

实施例的多线程 “哔” 的代码。此代码在Windows XP上按预期使用PC扬声器。在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); 
} 
+0

这是非常好的,但我不知道我将如何实施这样的解决方案。 这可能是迄今为止最好的答案,但我们对此非常青睐,所以我们都不了解这是什么。 时间不是一个特别的问题,流程(在我们的想法中)应该彼此并行运行,并且除了发送命令时不必同步运行。 – FAMICOMASTER

+0

@FAMICOMASTER - 我改变了我的答案,以演示使用Beep()播放“歌曲”的例子。 – rcgldr

+0

还没有尝试过,但这似乎是可行的。谢谢! – FAMICOMASTER