Iphone 间歇性extaudiofileread exc\u访问错误

Iphone 间歇性extaudiofileread exc\u访问错误,iphone,ios,exc-bad-access,Iphone,Ios,Exc Bad Access,我有一个目前看来无法解决的EXC\u BAD\u访问问题。 我尝试过启用NSZombie,这似乎是许多帖子中的建议,但我处理的是c指针,而不是objc对象,因此我没有得到任何有用的调试信息 我的代码的工作方式是,在需要磁盘上的一些音频之前,我分离一个新的posix线程,向它传递一个指向我想要的音频信息的指针。然后我看了一些样品。 我之所以选择posix而不是NSThread或NSOperation,是因为它似乎执行得更快。我的音频是cpu密集型的,所以我需要尽快阅读音频 如何修复此错误的访问错误

我有一个目前看来无法解决的EXC\u BAD\u访问问题。 我尝试过启用NSZombie,这似乎是许多帖子中的建议,但我处理的是c指针,而不是objc对象,因此我没有得到任何有用的调试信息

我的代码的工作方式是,在需要磁盘上的一些音频之前,我分离一个新的posix线程,向它传递一个指向我想要的音频信息的指针。然后我看了一些样品。 我之所以选择posix而不是NSThread或NSOperation,是因为它似乎执行得更快。我的音频是cpu密集型的,所以我需要尽快阅读音频

如何修复此错误的访问错误?它并非总是发生。有时它似乎发生在应用程序非常繁忙的时候。偶尔它根本不会发生

不管怎样,我可以试着抓住它作为一个快速解决方案吗?我还可以如何调查发生这种情况的原因

编辑这是我问的一个单独问题的链接,但它与同一个问题相关

[高强度io线程][1]

//detachnewthread gets called from remoteio callback

void detachnewthread(AudioSourceOBJ str)
{

    //..... code removed for brevity
    if(str)
    {

        int rc;

        rc = pthread_create(&str->thread, NULL, FetchAudio, (void *)str);
        if (rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }

    }

}


void *FetchAudio(void *threadid)
{ AudioSourceOBJ soundptr=threadid

AudioUnitSampleType *outSamplesChannelLeft;
AudioUnitSampleType *outSamplesChannelRight;

outSamplesChannelLeft                 = (AudioUnitSampleType *) soundptr->queuebuffer->ABL->mBuffers[0].mData;
outSamplesChannelRight  = (AudioUnitSampleType *)soundptr->queuebuffer->ABL->mBuffers[0].mData;
// ExtAudioFileRef audioFileRef;



// result=  ExtAudioFileOpenURL(str->path, &str->audioFileObject);

AudioStreamBasicDescription importFormat = {0};

size_t bytesPerSample = sizeof (AudioUnitSampleType);

// Fill the application audio format struct's fields to define a linear PCM, 
//        stereo, noninterleaved stream at the hardware sample rate.
importFormat.mFormatID          = kAudioFormatLinearPCM;
importFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
importFormat.mBytesPerPacket    = bytesPerSample;
importFormat.mFramesPerPacket   = 1;
importFormat.mBytesPerFrame     = bytesPerSample;
importFormat.mChannelsPerFrame  = 2;                    // 2 indicates stereo
importFormat.mBitsPerChannel    = 8 * bytesPerSample;
importFormat.mSampleRate        = 44100;


ExtAudioFileSetProperty (
                                     engineDescribtion.audiofilerefs[soundptr->audioindex],
                                     kExtAudioFileProperty_ClientDataFormat,
                                     sizeof (importFormat),
                                     &importFormat
                                     );

UInt32 numberofframestoread=(soundptr->amounttoread);
AudioBufferList *bufferList;

bufferList = (AudioBufferList *) malloc (
                                         sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
                                         );


// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;

// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < 2; arrayIndex++) {
    bufferList->mBuffers[arrayIndex] = emptyBuffer;
}

// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[0].mNumberChannels  = 1;
bufferList->mBuffers[0].mDataByteSize    = numberofframestoread * sizeof (AudioUnitSampleType);
bufferList->mBuffers[0].mData            = (AudioUnitSampleType*)calloc(numberofframestoread, sizeof(AudioUnitSampleType));

    bufferList->mBuffers[1].mNumberChannels  = 1;
    bufferList->mBuffers[1].mDataByteSize    = numberofframestoread * sizeof (AudioUnitSampleType);
    bufferList->mBuffers[1].mData            = (AudioUnitSampleType*)calloc(numberofframestoread, sizeof(AudioUnitSampleType));




AudioUnitSampleType *inSamplesChannelLeft=bufferList->mBuffers[0].mData;
AudioUnitSampleType *inSamplesChannelRight=bufferList->mBuffers[1].mData;



// UInt32 read=(UInt32)soundptr->fetchsample;
UInt32 read_plus_half_buffer=soundptr->fetchsample;

UInt32 readdestination= read_plus_half_buffer+numberofframestoread;
UInt32 actualsamplesread=0;

actualsamplesread=numberofframestoread;


if (readdestination>soundptr->perfectframecount) {


    UInt32 readinpt1=0;
    UInt32 readoutpt1=0;
    UInt32 readinpt2=0;
    UInt32 readoutpt2=0;
    Float32 readtillendamount=0;

    readinpt1=read_plus_half_buffer;
    readoutpt1=soundptr->perfectframecount;
    readinpt2=0;



    if(read_plus_half_buffer>soundptr->perfectframecount)
    {
        readtillendamount=numberofframestoread;
        readinpt1=read_plus_half_buffer-soundptr->perfectframecount;

    }else
    {

        readtillendamount=soundptr->perfectframecount - readinpt1;
        readoutpt2=numberofframestoread-readtillendamount;




    }
    actualsamplesread= readtillendamount;
    ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], readinpt1);
    ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&actualsamplesread , bufferList);

    int writeposition=soundptr->queuebuffer->position;

    for (int i=0; i<actualsamplesread; i++) {


        outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[i];
        outSamplesChannelRight[writeposition]=inSamplesChannelRight[i];



        writeposition++;

    }

    if (actualsamplesread!=readtillendamount) {

        UInt32 newzeroamount= readtillendamount-actualsamplesread;

        for (int j=0; j<newzeroamount; j++) {

            outSamplesChannelLeft[writeposition]=0;
            outSamplesChannelRight[writeposition]=0;
            writeposition++;

        }

    }       
    bufferList->mBuffers[1].mDataByteSize    = readoutpt2 * sizeof (AudioUnitSampleType);
    bufferList->mBuffers[0].mDataByteSize    = readoutpt2 * sizeof (AudioUnitSampleType);


    ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], 0);
    ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&readoutpt2 , bufferList);


    for (int k=0; k<readoutpt2; k++) {

        outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[k];
        outSamplesChannelRight[writeposition]=inSamplesChannelRight[k];
        writeposition++;

    }


}else if(readdestination<=soundptr->perfectframecount){

    ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], read_plus_half_buffer);

    bufferList->mBuffers[1].mDataByteSize    = actualsamplesread * sizeof (AudioUnitSampleType);
    bufferList->mBuffers[0].mDataByteSize    = actualsamplesread * sizeof (AudioUnitSampleType);
    // crash happens here

    if(bufferList)
    {
   assert( ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&actualsamplesread , bufferList));
    }else

    {
        printf("NO BUFFER");
    }



    int writeposition=soundptr->queuebuffer->position;
    for (int i=0; i<actualsamplesread; i++) {

        outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[i];
        outSamplesChannelRight[writeposition]=inSamplesChannelRight[i];
        writeposition++;

    }

    if (actualsamplesread!=numberofframestoread) {
        int zerosamples=0;

        zerosamples=numberofframestoread-actualsamplesread;

        for (int j=0; j<zerosamples; j++) {
            outSamplesChannelLeft[writeposition]=0;
            outSamplesChannelRight[writeposition]=0;
            writeposition++;


        }

    }                

}else
{
    printf("unknown condition");

}





free(bufferList->mBuffers[0].mData); 
free(bufferList->mBuffers[1].mData); 
free(bufferList);
bufferList=nil;

soundptr->queuebuffer->isreading=NO;

// pthread_detach(soundptr->thread);  
// free(&soundptr->m_lock);
return 0;
// pthread_exit(NULL);

这个问题几乎肯定会发生,因为你不应该读取内存。因此,
EXC\u BAD\u ACCESS
。重要的是,缓冲区的大小和你正在读取的内存量都是正确的。例如,如果你试图读取超过缓冲区值的内存,你会收到一个错误

ExtAudioFileRead
中,
&readoutpt2
处的值应指定帧数。您确定该值正确吗?
bufferList
是否足够大以存储该帧数?在读取数据时是否将指针向前移动
bufferList
,前进的量是否正确

您是否根据基础类型正确分配内存?例如,音频数据是整数格式还是浮点格式

基本上,所有的东西都需要正确地相加,否则你会在某个地方失去缓冲


另一个尝试跟踪内存问题的工具是
guard malloc
。您可以在此处找到更多信息我注意到代码中有以下几行:

bufferList = (AudioBufferList *) malloc (
                                         sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
                                         );
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;
您正在使AudioBufferList具有一个AudioBuffer的容量,但随后表明它实际上有两个。请尝试将“*(1)”更改为“*(2)”

除此之外,您不应该在线程中执行malloc或ExtAudioFileOpen,因为它们会占用时间。如果您能够设法预先执行malloc和ExtAudioFileOpen,并将它们保存在文件的结构数组中,您可能会发现性能/稳定性有所提高


我可能没有完全正确地阅读代码,因为它的格式似乎有点混乱,但我希望这会有所帮助。

您可以通过定位代码并找出错误原因来解决此问题,而不是尝试/捕获

Guard Malloc可以帮助您识别程序中的许多问题。这是一个可以在Xcode中启用的诊断选项。该选项的目的是在您尝试读取或写入您不拥有的内存时失败,使程序的哪个部分导致问题比通常更清楚。完整详细信息:
man guardmalloc
。第一个step是纠正guardmalloc指出的所有问题。您应该能够在没有这些问题的情况下运行应用程序数小时

如果您希望异常和运行时检查帮助您在前面(这些问题值得考虑)识别这些问题,请考虑C++实现而不是C实现。 更新


如果有问题的是堆分配,那么malloc日志记录可能会对您有所帮助。当启用malloc日志记录并且调试器暂停执行时,只需使用
malloc\u history
查看分配的调用堆栈。malloc\u history将查找日志中的地址并转储alloc创建的调用堆栈。从那里,您只需按照程序中的分配流程来查找错误所在。

我最终找到了这个问题的解决方案。每次需要音频时,我都会创建一个新线程来获取音频。有时,当线程为特定缓冲区获取音频时,同一缓冲区会再次请求数据同一缓冲区中的数据不能同时访问,因此exc\u访问错误

我解决了这个问题,只让一个线程等待,并被通知使用posix条件获取数据


这里的所有答案都很有用,并帮助我了解了很多调试方面的知识。谢谢各位。

是的,我确定readoutpt2值正确,我的bufferlist也是如此。示例的格式是什么?整数还是浮点数?您对缓冲区分配的计算是什么?有多少个通道?示例是有符号的16位整数,2个通道关于音频。作为一个最好的猜测,你会说问题与缓冲区列表有关,而不是从磁盘读取的实际音频?如果我同时访问8个音频源,一切都很好。除此之外,我得到了错误。是否可能是由于缺乏资源,线程中的代码没有完全执行,例如:创建缓冲区我会说它比我与缓冲区有关。缓冲区有多大?你是如何计算它们的大小的?每个缓冲区的最大大小是25600个样本*4字节。我在文章中包含了完整的函数。可能更容易查看,而不是试图解释。“似乎执行得更快”-除非你创建线程非常快,否则我非常怀疑用以创建你的线程会影响它们的性能。但是,请用一些基准来证明我是错误的;)你会考虑多快?我每秒要分离大约16到24个线程。这是不是太多了?我会觉得有点过分了。我会考虑重新思考这个体系结构。线程将开始超过th的好处
bufferList = (AudioBufferList *) malloc (
                                         sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
                                         );
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;