Results 1 to 6 of 6

Thread: Prevent concurrent access from different threads?

  1. #1
    Join Date
    Mar 2010
    Posts
    319
    Thanks
    1
    Thanked 14 Times in 12 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Prevent concurrent access from different threads?

    Hi, I was wondering whether I could have some views on the following.

    My application uses a thread to run a simulation and generate simulation data. A thread is used so that my application's GUI can remain responsive. Now, while a simulation is being run, my application's main thread makes successive calls to QTimer::singleShot() to fetch any new simulation data that has been generated, as well as to plot whatever the user wants to visualise. The user can decide on what to visualise by creating/removing traces, this through my application's GUI.

    If I pre-select some traces and run a simulation, then everything works as expected. However, if, during a simulation, I remove a trace, then my application may crash. This is because the fetching function I call from QTimer::singleShot() goes through all the different traces and update them. Now, if a trace has been removed during a simulation and, more importantly, in the middle of my fetching function, then my fetching function might try to use a trace which doesn't exist anymore, hence the crash.

    So, what would you do to avoid this problem? I originally thought I could solve this problem by using a mutex, but that failed and I believe this might be because of my fetching function being called through QTimer::singleShot() and therefore running in its own thread?

    Anyway, any idea/help on the above would be much appreciated...

    Cheers, Alan.

  2. #2
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Prevent concurrent access from different threads?

    mutexes/critical sections stop concurrent access from different threads.

    without seeing your code (read my sig), we can't say much more. It all depends how things go wrong when X uses Y that doesn't exist.

    You should ask yourself: If Y doesn't exist, why & how can X use it?

    Simply, you need a thread safe mechanism to remove traces - you will need to...

    Analyse where it is safe to do this (the range of the critical section(s)).
    Implement a mechanism (probably using signals/slots) that sends intention to remove traces from gui to simulation.
    Last edited by amleto; 25th February 2013 at 19:39.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  3. #3
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,017 Times in 4,793 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Prevent concurrent access from different threads?

    Quote Originally Posted by agarny View Post
    because of my fetching function being called through QTimer::singleShot() and therefore running in its own thread?
    Timers do not start any new threads.

    If using a mutex fails then apparently you're protecting the wrong resource or you're not protecting any resources at all.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  4. #4
    Join Date
    Mar 2010
    Posts
    319
    Thanks
    1
    Thanked 14 Times in 12 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Prevent concurrent access from different threads?

    amleto, I already use signals/slots to add/remove a trace (since it's done through my application's GUI). Anyway, you asked for some code, but it's not always easy to provide some but I have tried below...

    wysota, thanks, I wasn't sure about QTimer::singleShot() creating a new thread or not. I should have checked Qt's code and well... now, I have...

    My .cpp and .h files are as follows (to make it 'short', I removed comments and, I know, what I believe to be irrelevant code):

    Qt Code:
    1. class SingleCellSimulationViewWidget : public Core::ViewWidget
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. ...
    7.  
    8. private:
    9. ...
    10.  
    11. QMutex mSimulationMutex;
    12. QMutex mTracesMutex;
    13.  
    14. void updateResults(SingleCellSimulationViewSimulation *pSimulation,
    15. const qulonglong &pSize,
    16. const bool &pReplot = false);
    17.  
    18. void checkResults(SingleCellSimulationViewSimulation *pSimulation);
    19.  
    20. ...
    21.  
    22. private Q_SLOTS:
    23. ...
    24.  
    25. void resetFileTabIcon();
    26.  
    27. void showHideParameterPlot(const QString &pFileName,
    28. CellMLSupport::CellmlFileRuntimeModelParameter *pParameter,
    29. const bool &pShowParameterPlot);
    30.  
    31. void callCheckResults();
    32.  
    33. ...
    34. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void SingleCellSimulationViewWidget::resetFileTabIcon()
    2. {
    3. SingleCellSimulationViewSimulation *simulation;
    4.  
    5. {
    6. QMutexLocker mutexLocker(&mSimulationMutex);
    7.  
    8. simulation = mStoppedSimulations.first();
    9.  
    10. mStoppedSimulations.removeFirst();
    11. }
    12.  
    13. emit updateFileTabIcon(simulation->fileName(), QIcon());
    14. }
    15.  
    16. void SingleCellSimulationViewWidget::showHideParameterPlot(const QString &pFileName,
    17. CellMLSupport::CellmlFileRuntimeModelParameter *pParameter,
    18. const bool &pShowParameterPlot)
    19. {
    20. QString key = parameterKey(pFileName, pParameter);
    21.  
    22. QMutexLocker mutexLocker(&mTracesMutex);
    23. QwtPlotCurve *trace = mTraces.value(key);
    24.  
    25. if (trace && !pShowParameterPlot) {
    26. mActiveGraphPanel->plot()->removeTrace(trace);
    27.  
    28. mTraces.remove(key);
    29. } else if (!trace && pShowParameterPlot) {
    30. SingleCellSimulationViewSimulationResults *results = mSimulation->results();
    31.  
    32. double *yData;
    33.  
    34. ...
    35.  
    36. QwtPlotCurve *trace = mActiveGraphPanel->plot()->addTrace(results->points(), yData, results->size());
    37.  
    38. mTraces.insert(key, trace);
    39. }
    40. }
    41.  
    42. void SingleCellSimulationViewWidget::updateResults(SingleCellSimulationViewSimulation *pSimulation,
    43. const qulonglong &pSize,
    44. const bool &pReplot)
    45. {
    46. SingleCellSimulationViewSimulation *simulation = pSimulation?pSimulation:mSimulation;
    47.  
    48. if (simulation == mSimulation) {
    49. QMutexLocker mutexLocker(&mTracesMutex);
    50.  
    51. QMap<QString, QwtPlotCurve *>::const_iterator iter = mTraces.constBegin();
    52.  
    53. while (iter != mTraces.constEnd()) {
    54. QString fileName = iter.key();
    55.  
    56. ...
    57.  
    58. QwtPlotCurve *trace = iter.value();
    59.  
    60. if (!fileName.compare(mSimulation->fileName())) {
    61. double *yData;
    62.  
    63. ...
    64.  
    65. qulonglong oldSize = trace->dataSize();
    66.  
    67. trace->setRawSamples(simulation->results()->points(), yData, pSize);
    68.  
    69. if (!pReplot && (pSize > 1))
    70. qobject_cast<SingleCellSimulationViewGraphPanelPlotWidget *>(trace->plot())->drawTraceSegment(trace, oldSize?oldSize-1:0, pSize-1);
    71. }
    72.  
    73. ++iter;
    74. }
    75.  
    76. ...
    77. } else {
    78. ...
    79. }
    80. }
    81.  
    82. void SingleCellSimulationViewWidget::checkResults(SingleCellSimulationViewSimulation *pSimulation)
    83. {
    84. qulonglong simulationResultsSize = pSimulation->results()->size();
    85.  
    86. if (simulationResultsSize != mOldSimulationResultsSizes.value(pSimulation)) {
    87. mOldSimulationResultsSizes.insert(pSimulation, simulationResultsSize);
    88.  
    89. updateResults(pSimulation, simulationResultsSize);
    90. }
    91.  
    92. if (pSimulation->isRunning()) {
    93. mCheckResultsSimulations << pSimulation;
    94.  
    95. QTimer::singleShot(0, this, SLOT(callCheckResults()));
    96. }
    97. }
    98.  
    99. void SingleCellSimulationViewWidget::callCheckResults()
    100. {
    101. SingleCellSimulationViewSimulation *simulation;
    102.  
    103. {
    104. QMutexLocker mutexLocker(&mSimulationMutex);
    105.  
    106. simulation = mCheckResultsSimulations.first();
    107.  
    108. mCheckResultsSimulations.removeFirst();
    109. }
    110.  
    111. checkResults(simulation);
    112. }
    To copy to clipboard, switch view to plain text mode 

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,017 Times in 4,793 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Prevent concurrent access from different threads?

    And where are the threads involved here? I see a couple of problems with your code related to threading but first I'd like to know if we do have any multithreading here at all.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. #6
    Join Date
    Mar 2010
    Posts
    319
    Thanks
    1
    Thanked 14 Times in 12 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Prevent concurrent access from different threads?

    Quote Originally Posted by wysota View Post
    And where are the threads involved here? I see a couple of problems with your code related to threading but first I'd like to know if we do have any multithreading here at all.
    Exactly, the mutexes I use in the code I gave are all in functions called from the same thread and therefore unnecessary. I have just had a chat with someone and to cut a long story short, I needed to learn more about Qt's event loop, and now that I know a bit more about it, I can see that my mutexes were unnecessary and the fact that my application crashes is most likely due to some non-reentrant / non-atomic functions, from two different threads, which access some shared data for reading and/or writing purposes. So, yes, I am still very much learning (the hard way) about threading...

Similar Threads

  1. Replies: 17
    Last Post: 11th April 2013, 09:35
  2. how to debugger Qt concurrent with GDB
    By learning_qt in forum Qt Programming
    Replies: 0
    Last Post: 8th November 2010, 12:13
  3. concurrent signals handling
    By s_stavrev in forum Qt Programming
    Replies: 2
    Last Post: 4th July 2010, 15:16
  4. How do I access data between threads
    By yodasoda in forum Qt Programming
    Replies: 3
    Last Post: 26th February 2010, 19:10
  5. Concurrent progress reporting
    By chezifresh in forum Qt Programming
    Replies: 1
    Last Post: 30th June 2008, 08:47

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.