Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug report: When sub-task are performed quickly, the results are inaccurate #39

Open
muyuuuu opened this issue Aug 13, 2021 · 4 comments

Comments

@muyuuuu
Copy link

muyuuuu commented Aug 13, 2021

#include <iostream>

#include "../include/ThreadPool.h"

class TEST {
private:
  std::mutex mtx;
  std::vector<int> v1[2];
  std::priority_queue<int> q;
public:
  void init() {
    v1[0].push_back(1);
    v1[0].push_back(2);
    v1[0].push_back(3);

    v1[1].push_back(1);
    v1[1].push_back(3);
    v1[1].push_back(2);
  }
  
  void push(const int& index) {
    for (auto& i : v1[index]) {
      std::lock_guard<std::mutex> m{mtx};
      q.push(i);
    }
  }

  void run() {
    ThreadPool pool(2);
    pool.init();
    // https://github.com/mtrebi/thread-pool/issues/14
    // https://github.com/mtrebi/thread-pool/issues/7
    for (int i = 0; i < 100; i++) {
      for (int j = 0; j < 2; j++) {
        auto func = std::bind(&TEST::push, this, j);
        pool.submit(func);
      }
    }
    pool.shutdown();

    int tmp{-2};
    std::cout << q.size() << std::endl;
  }
};

int main(int argc, char *argv[]) {
  TEST t;
  t.init();
  t.run();
  return 0;
}

The output of the above code is not accurate.

315 // sometimes
291 // sometimes
69 // sometimes
@muyuuuu
Copy link
Author

muyuuuu commented Aug 13, 2021

If I add thread-sleep, the results will be 6.

void push(const int& index) {
  std::this_thread::sleep_for(std::chrono::milliseconds(2000));
  for (auto& i : v1[index]) {
    std::lock_guard<std::mutex> m{mtx};
    q.push(i);
  }
}

Is there some bugs?

@muyuuuu
Copy link
Author

muyuuuu commented Aug 14, 2021

when pool.shutdown() was runned, I found that m_queue.size() isn't equal to zero. How to fix it up? I'll try to fix it.

@muyuuuu
Copy link
Author

muyuuuu commented Aug 14, 2021

I wrote an inelegant solution. When the thread pool is closed, the task queue is checked to see if there are any tasks left. If so, execution continues.

void shutdown() {
  m_shutdown = true;
  m_conditional_lock.notify_all();
  for (int i = 0; i < m_threads.size(); ++i) {
    if(m_threads[i].joinable()) {
      m_threads[i].join();
    }
  }

  bool dequeued;
  std::function<void()> func;
  while (m_queue.size()) {
    {
      std::unique_lock<std::mutex> lock(m_conditional_mutex);
      dequeued = m_queue.dequeue(func);
    }
    if (dequeued) {
      func();
    }
  }
}

But this would lose the performance benefits of multithreading. Is there a better solution?

@muyuuuu
Copy link
Author

muyuuuu commented Aug 14, 2021

OK, I think this plan is better. I will send pull request, Thank you for writing such good code that I can use in my application program.

void operator()() {
  std::function<void()> func;
  bool dequeued;
  while (!m_pool->m_shutdown) {
    {
      std::unique_lock<std::mutex> lock(m_pool->m_conditional_mutex);
      if (m_pool->m_queue.empty()) {
        m_pool->m_conditional_lock.wait(lock);
      }
      dequeued = m_pool->m_queue.dequeue(func);
    }
    if (dequeued) {
      func();
    }
  }

  // If the task queue is not empty, continue obtain task from task queue, 
  // the multithread continues execution until the queue is empty
  while (!m_pool->m_queue.empty()) {
    {
      std::unique_lock<std::mutex> lock(m_pool->m_conditional_mutex);
      dequeued = m_pool->m_queue.dequeue(func);
      if (dequeued) {
        func();
      }
    }
  }
}

muyuuuu added a commit to muyuuuu/thread-pool that referenced this issue Aug 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant