0

I am having issues in a code having structure similar to the following minimum example. There is only one instance of MainClass. It makes new instance of Classlet on each call to its MainClass::makeclasslet()

I have multiple classlets writing to a single list buffer. After some time I need to copy/ dump the values from list buffer (FIFO).

The problem is that I am getting the following output in MainClass::clearbuffer()

>>>>>>>>>> 704 >>>>>>>>>>>>>>>>>>> Buffer size: 65363..... 1

I am unable to understand why the std::list::empty() returns true even when the buffer is locked with an atomic bool flag. I have tried moving the call to clearbuffer() (in addval()) to the main application thread so that not each Classlet event calls clearbuffer(). I have also tried adding delay QThread::msleep(10); after setting busy = true;. But some time after the application starts, I am getting the output shown above. Instead of popping all 65363+704 values in the list, it only popped 704 and broke the loop on list::isempty() being true (apparently).

class MainClass : public QObject {
Q_OBJECT

    private:
        std:: list<int> alist;
        std::atomic<bool> busy;
    MainClass() {
        busy = false;
    }
    ~MainClass() {
        // delete all classlets
    }
    void makeclasslet() {
        Classlet newclasslet = new Classlet();
        // store the reference
    }
    void addval(int val) {
        alist.push_back(val);
        if (alist.size() > 100)
        {
            if (!busy)
            {
                clearbuffer();
            }
        }
    }
    void clearbuffer() {
        if (!busy)
        {
            busy = true;

            int i = 0;
            while (!alist.empty())
            {
                i = i + 1;
                // save alist.front() to file
                alist.pop_front();
            }
            printf(">>>>>>>>>> %d >>>>>>>>>>> Buffer size: %d ..... %d\n", i, m_lstCSVBuffer.size(), m_lstCSVBuffer.empty());
            busy = false;
        }
    }
}
class Classlet {
    private:
        Mainclass* parent;
    void onsomeevent(int val) {
        parent->addval(val);
    }
}

I am using qt5.9 on Ubuntu 18.04. GCC/ G++ 7.5.0

  • Are you adding elements to the list using multiple threads? – Guillaume Racicot Aug 13 '20 at 12:42
  • 4
    You can't use atomic bools for multithreading like this. It's called atomic because the operations *on the boolean value* are atomic. This doesn't prevent two threads from getting into `clearbuffer()` simultaneously and then both setting busy = true. For this kind of synchronization try [`std::mutex`](https://en.cppreference.com/w/cpp/thread/mutex) – shananton Aug 13 '20 at 12:49
  • 5
    `if (!busy) { busy = true; ...stuff to do... busy = false }` -- This is not atomic. – PaulMcKenzie Aug 13 '20 at 12:49
  • Also, even if you attempted to use the atomic, [this is probably what you should be using](https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange). A naive `if (!busy) { busy = true;` is not how you do things like this. – PaulMcKenzie Aug 13 '20 at 12:56
  • @GuillaumeRacicot yes. – speedbooster Aug 17 '20 at 04:56
  • @PaulMcKenzie trying the suggestions now. Thank you! – speedbooster Aug 17 '20 at 04:57
  • @PaulMcKenzie Could you please explain: "The weak forms ((1) and (3)) of the functions are allowed to fail spuriously, that is, act as if *obj != *expected even if they are equal." – speedbooster Aug 17 '20 at 05:15
  • how do i choose shanaton and PaulMcKenzie's comments as answers? I have solved the problem using @shananton's solution. – speedbooster Aug 20 '20 at 05:06

0 Answers0