【问题标题】:C++ Threads - CrashesC++ 线程 - 崩溃
【发布时间】:2015-05-28 15:52:03
【问题描述】:

我整天都在寻找解决方案,但没有任何结果。你是唯一的希望。

我必须做基于 bass.h 库的声音合成器。一切正常,直到我希望它播放单独的流。我决定在不同的线程上做:

void Synthezator::play(MonoStream *stream1, MonoStream *stream2)
{
    threadParam data = {stream1, this};
    threadParam data2 = {stream2, this};
    int x = 6;
    DWORD threadId;
    DWORD threadId2;
    //thread first (PlayThread, data);
    //thread second (PlayThread, data2);
    //first.join();
    //second.join();
    CreateThread(NULL, 0, PlayThread, (PVOID) &data, 0, &threadId);
    CreateThread(NULL, 0, PlayThread, (PVOID) &data2, 0, &threadId2);
    getchar();  
}

(注释的也一样)

只有当两个线程都在工作时,崩溃才会随机发生(随机发生,而不是每次)。如果我评论其中一个 - 没有崩溃。

PlayThread 函数:

DWORD WINAPI Synthezator::PlayThread(PVOID data)
{
    //cout << "kurwa";
    int i=0;
    threadParam* dataNew = (threadParam*) data;
    dataNew->stream->SeekBegin();
    while(!(dataNew->stream->eof()))
    {
        int no = 0;
        note* a = dataNew->stream->Next(&no);
        dataNew->pointer->PlayNote(a, no);
        i++;
    }
} 

播放笔记:

void Synthezator::PlayNote(note* note, int count)
{
    position = new double[count];
    generatorParams params = {synthType, count, note, position, this};
    HSTREAM SignalStream = BASS_StreamCreate (FREQUENCY, 1, 0, &Generator, &params);
    if (SignalStream == 0) throw " Cannot create stream";

    if(note->sound != 0) {
        if (!BASS_ChannelPlay (SignalStream, TRUE)) throw "Cannot play generated sample";
    }
    const int secinusecs = 1000000;
        sleep(secinusecs*floor(note->duration)/1000000);
        usleep(secinusecs*(note->duration-floor(note->duration)));
    if(note->sound != 0) {
        BASS_ChannelStop(SignalStream);
    }
    BASS_StreamFree(SignalStream);
    delete [] position; 
}

如果我评论这一行,就没有崩溃(但也没有声音):

if (!BASS_ChannelPlay (SignalStream, TRUE)) throw "Cannot play generated sample";

【问题讨论】:

  • 从 PlayThread 中的第一个 cout 来看,您已经为此苦苦挣扎了一段时间:D
  • 位置变量在哪里声明?由2个线程同时修改!
  • 删除行“删除[]位置;”解决了这个问题。谢谢!
  • 不,它没有 - 你现在有内存泄漏(内存已分配,没有人释放它)!
  • threadParam datathreadParam data2 是 play() 中的局部变量。当比赛结束时,这些将不再有效。因此,如果您的线程在播放完成后访问它们,您将拥有 UB。虽然我猜这就是 getchar() 的意义所在。

标签: c++ multithreading crash


【解决方案1】:

创建线程:

threadParam data = {stream1, this};
threadParam data2 = {stream2, this};
CreateThread(NULL, 0, PlayThread, (PVOID) &data, 0, &threadId);
CreateThread(NULL, 0, PlayThread, (PVOID) &data2, 0, &threadId2);

线程内部

dataNew->pointer->PlayNote(a, no);

问题是您在两个不同的位置使用相同的对象 PlayNote 功能。因此在线程 1 完成 PlayNote 之前,线程 2 进入 PlayNote。 PlayNote 中的第一件事是存储在对象中的动态内存分配,因此线程 2 只是丢弃了线程 1 的指针。此时线程 1 的行为变得不确定,并且在第一个线程完成函数并删除指针后,一旦另一个线程切换回 contex,就保证会发生崩溃。

欢迎来到多线程编程。这是你的帽子。

【讨论】:

  • 我没有编辑那些对象,所以我不明白为什么我不应该使用它们。无论如何,删除行“删除[]位置;”解决了问题。
  • 当您修改位置时,您正在编辑 PlayNote 中的对象。并且通过删除删除,您会引入内存泄漏,并且会在崩溃发生时导致不确定的行为。将位置设置为 PlayNote 本地,保留在删除中是更好的解决方案。
【解决方案2】:

如果position 成员是您在不同线程中修改的唯一成员,那么我建议您放回delete [] position; 行并将位置声明为私有变量:double* position = new double[count];

这样每个线程都会有自己的位置数组。

虽然我必须查看整个代码才能确定其他成员没有被多个线程修改。

【讨论】:

    猜你喜欢
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    • 2018-09-05
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多