You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When i run the StandaloneOscilloscopeSpectralAnalyzer i get an "abort() has been called" error...
Sometimes is occurs immediately, and sometimes it takes a while.
It could also be nice if you have made visual studio project for the application.
Could you give some more information about the system that triggers the error? Have you run it under a debugger? A stack trace would be great to track the source of the error down.
Regarding Visual Studio, I didn't try it on Windows so far, but as JUCE is cross platform I would expect it to just work. You can simply add a Visual Studio exporter in the Projucer yourself. I will add one if I found some time to test it on Windows...
Stack trace
!std::_Mtx_unlockX(_Mtx_internal_imp_t * _Mtx) Line 87
!std::_Mutex_base::unlock() Line 60
!ntlab::DataCollector::finishedReading() Line 127
!ntlab::LocalDataSinkAndSource::finishedReading(ntlab::VisualizationTarget & target) Line 83
!ntlab::OscilloscopeComponent::endFrame() Line 209
!ntlab::Plot2D::renderOpenGL() Line 503
It seams to be happening when writeBufferLock.unlock it called.
void finishedReading()
{
if (readBlock.getSize() != expectedBlockSize)
readBlock.setSize(expectedBlockSize, true);
if (readerShouldSwapBlocks)
{
writeBlock.swapWith(readBlock);
writeBufferLock.unlock(); <------
readerShouldSwapBlocks = false;
dataBlockReady(sinkIdx);
}
readBufferLock.unlock();
};
which call unlock on the mutex
void unlock()
{ // unlock the mutex
_Mtx_unlockX(_Mymtx());
}
which call _Mtx_unlockX on xthread
inline int _Mtx_unlockX(_Mtx_t _Mtx)
{ // throw exception on failure
return (_Check_C_return(_Mtx_unlock(_Mtx)));
}
ant the _Check_C_return is throwing the _CRTIMP2_PURE void __cdecl _Throw_C_error(int _Code); exception...
(Press Retry to debug the application)
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
Note: my test application is called opengl but contains your example.
The modified DataCollector.h
/*
MIT License
Copyright (c) 2018 Janos Buttgereit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <JuceHeader.h>
#include < mutex >
namespace ntlab
{
class RealtimeDataSink;
/**
* A base class for all objects collecting some data from the realtime stream, preprocesses this data and then
* transmits the processed result to a RealtimeDataSink instance that manages the transport of the collected
* data to the visualization target. To keep it as abstract and extendable as possible, juce::MemoryBlocks are
* used to exchange the preprocessed data, allowing to exchange any kind of data.
* @see RealtimeDataSink, VisualizationTarget
*/
class DataCollector
{
public:
/** The identifier string must be the same on the visualization side to map both instances */
DataCollector (const juce::String& idenfifier) : id (idenfifier) {};
virtual ~DataCollector () {};
/** This can be used to send settings from the target to the DataCollector */
virtual void applySettingFromTarget (const juce::String& setting, const juce::var& value) {};
/** Returns immediately and causes the memory blocks managed by this class to resize before the next usage */
void resizeMemoryBlock (size_t newSizeInBytes)
{
expectedBlockSize = newSizeInBytes;
};
/** Called to begin writing to a memory block. It won't be swapped until finishedWriting was called */
juce::MemoryBlock* startWriting()
{
if (writeBufferLock.try_lock())
{
DBG("writeBufferLock try_lock=true");
return &writeBlock;
}
else
{
DBG("writeBufferLock try_lock=false");
}
return nullptr;
};
/**
* Always call this after having finished writing to release the block for swapping and invoking the next
* dataBlockReady call.
*/
void finishedWriting()
{
if (readBufferLock.try_lock())
{
DBG("readBufferLock try_lock=true");
writeBlock.swapWith (readBlock);
DBG("writeBufferLock unlock");
writeBufferLock.unlock();
DBG("writeBufferLock unlocked");
DBG("readBufferLock unlock");
readBufferLock.unlock();
DBG("readBufferLock unlocked");
dataBlockReady (sinkIdx);
}
else {
DBG("readBufferLock try_lock=false");
readerShouldSwapBlocks = true;
}
};
/**
* This is called to indicate that the sink can now read a new data block. It doesn't have to use it
* but can also just poll startReading on a regular basis. The Lambda should be assigned by
* RealtimeDataSink when adding it to the sink. As this will be called from the realtime thread, it should
* return as fast as possible
*/
std::function<void(int)> dataBlockReady = [](int) {};
/**
* Called by the sink to start reading from the block. The caller might swap the block supplied with
* another block
* */
juce::MemoryBlock& startReading()
{
try
{
DBG("readBufferLock lock");
readBufferLock.lock();
DBG("readBufferLock locked");
}
catch (int e)
{
int i = 0;
i++;
}
return readBlock;
};
/** Called by the sink to indicate that it has finished reading */
void finishedReading()
{
if (readBlock.getSize() != expectedBlockSize)
readBlock.setSize(expectedBlockSize, true);
if (readerShouldSwapBlocks)
{
writeBlock.swapWith(readBlock);
DBG("writeBufferLock unlock");
writeBufferLock.unlock();
DBG("writeBufferLock unlocked");
readerShouldSwapBlocks = false;
dataBlockReady(sinkIdx);
}
DBG("readBufferLock unlock");
readBufferLock.unlock();
DBG("readBufferLock unlocked");
};
/** For internal use only, don't change */
int sinkIdx = -1;
/** For internal use only, don't change */
RealtimeDataSink *sink = nullptr;
const juce::String id;
private:
juce::MemoryBlock readBlock;
juce::MemoryBlock writeBlock;
bool readerShouldSwapBlocks = false;
std::mutex readBufferLock, writeBufferLock;
size_t expectedBlockSize = 0;
};
@flamsk How did you get the module to compile under Windows? I am compiling with VS2019 on Windows 10 via Parallels, and get lots of errors e.g. GL_ARRAY_BUFFER undefined
Activity
JanosGit commentedon Jun 19, 2019
Could you give some more information about the system that triggers the error? Have you run it under a debugger? A stack trace would be great to track the source of the error down.
Regarding Visual Studio, I didn't try it on Windows so far, but as JUCE is cross platform I would expect it to just work. You can simply add a Visual Studio exporter in the Projucer yourself. I will add one if I found some time to test it on Windows...
flamsk commentedon Jun 19, 2019
I have been running it under debug.
Stack trace
!std::_Mtx_unlockX(_Mtx_internal_imp_t * _Mtx) Line 87
!std::_Mutex_base::unlock() Line 60
!ntlab::DataCollector::finishedReading() Line 127
!ntlab::LocalDataSinkAndSource::finishedReading(ntlab::VisualizationTarget & target) Line 83
!ntlab::OscilloscopeComponent::endFrame() Line 209
!ntlab::Plot2D::renderOpenGL() Line 503
It seams to be happening when writeBufferLock.unlock it called.
void finishedReading()
{
if (readBlock.getSize() != expectedBlockSize)
readBlock.setSize(expectedBlockSize, true);
if (readerShouldSwapBlocks)
{
writeBlock.swapWith(readBlock);
writeBufferLock.unlock(); <------
readerShouldSwapBlocks = false;
dataBlockReady(sinkIdx);
}
readBufferLock.unlock();
};
which call unlock on the mutex
void unlock()
{ // unlock the mutex
_Mtx_unlockX(_Mymtx());
}
which call _Mtx_unlockX on xthread
inline int _Mtx_unlockX(_Mtx_t _Mtx)
{ // throw exception on failure
return (_Check_C_return(_Mtx_unlock(_Mtx)));
}
ant the _Check_C_return is throwing the _CRTIMP2_PURE void __cdecl _Throw_C_error(int _Code); exception...
flamsk commentedon Jun 19, 2019
I just tried to add a lot of logging around the locks and when it fails i see the following in output:
readBufferLock locked
readBufferLock unlock
readBufferLock unlocked
writeBufferLock try_lock=true
readBufferLock try_lock=true
writeBufferLock unlock
writeBufferLock unlocked
readBufferLock unlock
readBufferLock unlocked
writeBufferLock try_lock=true
readBufferLock try_lock=true
writeBufferLock unlock
writeBufferLock unlocked
readBufferLock unlock
readBufferLock unlocked
writeBufferLock try_lock=true
readBufferLock try_lock=true
writeBufferLock unlock
writeBufferLock unlocked
readBufferLock unlock
readBufferLock unlocked
writeBufferLock try_lock=true
readBufferLock try_lock=true
writeBufferLock unlock
writeBufferLock unlocked
readBufferLock unlock
readBufferLock unlocked
readBufferLock lock
writeBufferLock try_lock=true
readBufferLock locked
readBufferLock try_lock=false
writeBufferLock unlock
Debug Error!
Program: ...jects\OpenGl\Builds\VisualStudio2017\x64\Debug\App\OpenGl.exe
abort() has been called
(Press Retry to debug the application)
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
writeBufferLock try_lock=false
Note: my test application is called opengl but contains your example.
The modified DataCollector.h
/*
MIT License
Copyright (c) 2018 Janos Buttgereit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <JuceHeader.h>
#include < mutex >
namespace ntlab
{
class RealtimeDataSink;
}
flamsk commentedon Jun 19, 2019
would it be better to use the lock functionallity within Juce??
https://docs.juce.com/master/group__juce__core-threads.html
adamski commentedon Sep 20, 2019
@flamsk How did you get the module to compile under Windows? I am compiling with VS2019 on Windows 10 via Parallels, and get lots of errors e.g.
GL_ARRAY_BUFFER undefinedSimonHGit commentedon Sep 24, 2021
@adamski Maybe its outdated, but if someone will go into errors like
GL_ARRAY_BUFFER undefinedit worked for me by addingusing namespace juce;//todo: update to a newer version of juce to define this in juce_gles2.h#define GL_ALIASED_LINE_WIDTH_RANGE 0x846EBut to come to the reported issue:

Since I configured my App to use ASIO devices it runns into this debug error too: