【问题标题】:Asynchronous threads in C++C++ 中的异步线程
【发布时间】:2017-09-13 10:35:53
【问题描述】:

我们正在使用 Visual Studio 2005 开发 C++ 游戏(我们的一些计算机仍在运行 Windows 2000,这是可以运行的最新版本,无论如何我们都无法轻松将其转换为较新的版本)。

我们的作曲家已经写了几首短曲来测试系统,但是出现了一个问题: 播放音乐或音效时游戏卡住。

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

我认为我们可能可以在后台创建第二个线程或进程来循环播放指定的曲目,但是当我搜索时我找不到任何可以解决这个问题的东西,因为需要进行数据传输(尽管是单向的)两个进程之间。

在我看来,我们应该能够从包含要播放的曲目号的主程序向音乐进程传递一个命令——这应该相当简单,但我们最近已经转移到 C++ 并且没有目前对此非常有经验。

感谢您的任何建议。

附:请不要评论我们使用过时的软件,我们这样做是为了好玩,根本不打算投入任何资金。

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

音乐只使用 Beep();命令内置在标准 Windows 头文件 (windows.h) 中。

我们希望与主程序并行运行一个辅助进程以允许播放背景音乐。

如果事实证明这两个进程之间的数据传输太难了,我们是否可以在它打开时将一个起始变量作为轨道号传递给它,并在它完成后简单地杀死它?

【问题讨论】:

  • MSDN 上有描述 WIN32 的multithreading 功能的资源。如果无法访问 <thread> 库等较新的 C++ 功能,您最终将不得不使用 WIN32 系统调用手动完成很多工作。
  • 如果你只传输一个轨道号,只需使用一些原子 int 'trackNum' var,并让声音线程在到达轨道末尾并需要选择嵌套的时候读取它, (或重复相同的)。如果你需要停止它,你可以安排'-1'来表示'停止播放并等待一个事件'。
  • 是的,但是我们如何创建新线程并允许这样做呢?能举个简单的例子吗?
  • 如果您使用 MFC,请参阅:msdn.microsoft.com/en-us/library/s3w9x78e(v=vs.80).aspx 如果您使用直接 WIn32,请参阅:msdn.microsoft.com/en-us/library/windows/desktop/…
  • “游戏在播放音乐或音效时卡住”这听起来像是您需要查找和修复的错误,而不是通过线程等添加更多复杂性(和更多错误)。跨度>

标签: c++ multithreading visual-studio visual-c++


【解决方案1】:

在 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);
}

【讨论】:

  • 这很好,但我不确定如何实施这样的解决方案。到目前为止,这可能是最好的答案,但我们对此非常陌生,所以我们都不明白这是什么。时间不是一个特别的问题,进程(在我们看来)应该彼此并行运行,并且根本不需要同步运行,除非发送命令。
  • @FAMICOMASTER - 我更改了答案以显示使用 Beep() 播放“歌曲”的示例。
  • 还没有尝试过,但这似乎会奏效。谢谢!
猜你喜欢
  • 2021-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多