2017-04-10 59 views
1

似乎是thread1功能并没有得到执行C++线程不执行

#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; 
} 

我的Mac上的输出是1 2 1 2但在我的Ubuntu其1 1 1。我正在编译g++ -std=c++11 -pthread -o thread.out thread.cpp && ./thread.out。我错过了什么吗?

+0

不能保证在主循环再次锁定之前,thread1将能够获取互斥锁。这就是多线程的方式,它可能是不可预测的。 –

+0

但我认为thread1中的条件变量会用等待锁定互斥锁,并同时将main和thread1同步。我能做些什么来同步顺序运行? – Seph

+0

你有一个竞争条件。 ''thread''可以在'main'执行'queue.push(1)'时执行'queue.size()',并且行为是不确定的。 – GManNickG

回答

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; 
} 
2

此:

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

是不确定的行为。 for循环从0到size运行size+1次。我建议你写的更地道风格的队列:

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

当我coliru运行此,我以为运行某种* nix的机器,我得到4 1的:http://coliru.stacked-crooked.com/a/8de5b01e87e8549e

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

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

*请注意,即使您的4个元素不变的队列,并不真正是一个不变量。当队列中有3个元素时,线程可能(虽然不太可能)在同一时刻同时传递while条件。首先获得锁,然后推动另一个。所以你可以在队列中包含5个元素! (如你所见,异步编程很棘手)。特别是当你有锁的时候,你真的需要检查队列的大小,以便它能够工作。