c++ thread does not execute

时间:2017-04-10 03:23:21

标签: c++ multithreading

The thread1 function does not seem to get executed

   #include <iostream>
   #include <fstream>
   #include <thread>
   #include <condition_variable>
   #include <queue>

   std::condition_variable cv;
   std::mutex mu;
   std::queue<int> queue;
   bool ready;

    static void thread1() {
        while(!ready) {std::this_thread::sleep_for(std::chrono::milliseconds(10));}

        while(ready && queue.size() <= 4) {
                std::unique_lock<std::mutex> lk(mu);
                cv.wait(lk, [&]{return !queue.empty();});

                queue.push(2);
        }
    }

    int main() {
        ready = false;
        std::thread t(thread1);

        while(queue.size() <= 4) {
            {
                std::lock_guard<std::mutex> lk(mu);
                queue.push(1);
            }

            ready = true;
            cv.notify_one();
        }

        t.join();

        for(int i = 0; i <= queue.size(); i++) {
                int a = queue.front();
                std::cout << a << std::endl;
                queue.pop();
        }

        return 0;
}

On my Mac the output is 1 2 1 2 but in my ubuntu its 1 1 1. I'm compiling with g++ -std=c++11 -pthread -o thread.out thread.cpp && ./thread.out. Am I missing something?

2 个答案:

答案 0 :(得分:2)

此:

for(int i = 0; i <= queue.size(); i++) {
    int a = queue.front();
    std::cout << a << std::endl;
    queue.pop();
}

是未定义的行为。从0到size的for循环运行size+1次。我建议你用更惯用的方式写一个队列:

while(!queue.empty()) {
    int a = queue.front();
    std::cout << a << std::endl;
    queue.pop();
}

当我在coliru上运行时,我假设运行了某种* nix机器,我得到4 1&#39; s http://coliru.stacked-crooked.com/a/8de5b01e87e8549e

同样,您还没有指定任何会强制每个线程运行一定次数的内容。您只能(尝试*)导致队列达到大小4的不变量,无论哪种方式。恰好在我们运行它的机器上,线程2从未设法获取互斥锁。

如果您在不同点添加更多工作或甚至(仅用于教学目的)延迟,此示例将更有趣。模拟两个线程实际上正在工作。如果你在不同的点添加睡眠,你可以确保两个线程交替,虽然取决于你添加它们的位置,你可能会看到线程中断的4个元素的不变量!

*请注意,即使您的队列中的4个元素不变,也不是真正的不变量。当队列中有3个元素时,两个线程在完全相同的时刻传递while条件是可能的(尽管非常不可能)。首先获得锁定然后推动锁定,然后推动另一个锁定。所以你最终可以在队列中有5个元素! (正如您所看到的,异步编程很棘手)。特别是当你有锁时,你真的需要检查队列大小才能使其工作。

答案 1 :(得分:0)

我能够通过使第二个线程在单独的条件变量上的单独谓词上等待来解决这个问题。我不确定queue.size()是否是线程安全的。

#include <iostream>
#include <fstream>
#include <thread>
#include <condition_variable>
#include <queue>

std::condition_variable cv;
std::condition_variable cv2;
std::mutex mu;
std::queue<int> queue;
bool tick;
bool tock;

static void thread1() {
while(queue.size() < 6) {
    std::unique_lock<std::mutex> lk(mu);
    cv2.wait(lk, []{return tock;});

    queue.push(1);

    tock = false;
    tick = true;
    cv.notify_one();
}
}

int main() {
tick = false;
tock = true;
std::thread t(thread1);

while(queue.size() < 6) {
    std::unique_lock<std::mutex> lk(mu);
    cv.wait(lk, []{return tick;});

    queue.push(2);

    tick = false;
    tock = true;
    cv2.notify_one();
}

t.join();

while(!queue.empty()) {
    int r = queue.front();
    queue.pop();

    std::cout << r << std::endl;
}

return 0;
}