C++ 使用循环使同一线程不在没有睡眠的情况下一次又一次地获得相同的互斥

C++ 使用循环使同一线程不在没有睡眠的情况下一次又一次地获得相同的互斥,c++,multithreading,c++11,mutex,condition-variable,C++,Multithreading,C++11,Mutex,Condition Variable,我想在两个线程中计算两件事,每个线程都有一个无止境的循环。这两个人并不相互依赖 此外,我希望终端上的一些输出也是在一个无止境的循环中(只要在每次计算最后一个输出时重新开始,而不需要中间的任何步骤)。因此,我希望全局变量的一些局部副本(第一次计算的两个连续迭代和第二次计算的一个值)都处于安全状态 现在的问题是,我必须在这两个计算中添加一些睡眠,才能从func1获得一些输出。我检查了CPU的使用情况,睡眠肯定会降低CPU的使用率。 我怎样才能解决这个问题 另请参见测试注释: #include <

我想在两个线程中计算两件事,每个线程都有一个无止境的循环。这两个人并不相互依赖

此外,我希望终端上的一些输出也是在一个无止境的循环中(只要在每次计算最后一个输出时重新开始,而不需要中间的任何步骤)。因此,我希望全局变量的一些局部副本(第一次计算的两个连续迭代和第二次计算的一个值)都处于安全状态

现在的问题是,我必须在这两个计算中添加一些睡眠,才能从func1获得一些输出。我检查了CPU的使用情况,睡眠肯定会降低CPU的使用率。 我怎样才能解决这个问题

另请参见测试注释:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>

int n(0);
long s(1234);
double t(56.78);

std::condition_variable cond;
std::mutex m1;
std::mutex m2;

void func1() {
    while (true) {
        // Not needed due to wait unlocking the mutex
        //std::this_thread::sleep_for(std::chrono::nanoseconds(1));

        std::unique_lock<std::mutex> lck1(m1);
        cond.wait(lck1);
        int n1(n);
        long s1(s);
        cond.wait(lck1);
        int n2(n);
        long s2(s);
        lck1.unlock();

        std::unique_lock<std::mutex> lck2(m2);
        double ti(t);
        lck2.unlock();

        // calculate and print some output
        std::this_thread::sleep_for(std::chrono::milliseconds((n1*n2)/2));
        std::cout << n1 << ":" << s1 << ", " << n2 << ":" << s2 << ", " << ti << std::endl;
    }
}

void func2() {
    while (true) {
        // Why do I need this to make func1 ever proceed (ok, really seldom and random func1 got the mutex) and
        // how to work around this without sleep lowering time for computations?
        std::this_thread::sleep_for(std::chrono::nanoseconds(1)); // comment out to test

        std::unique_lock<std::mutex> lck1(m1);

        n++;

        // do some stuff taking some time with s
        std::this_thread::sleep_for(std::chrono::milliseconds((n*n)/3));

        cond.notify_all();
    }
}

void func3() {
    while (true) {
        // Why do I need this to make func1 ever proceed (it got the mutex never ever) and
        // how to work around this without sleep lowering time for computations?
        std::this_thread::sleep_for(std::chrono::nanoseconds(1)); // comment out to test

        std::unique_lock<std::mutex> lck2(m2);
        // do something taking some time with t
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
}

int main() {

    std::thread t1(func1);
    std::thread t2(func2);
    std::thread t3(func3);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}
#包括
#包括
#包括
#包括
int n(0);
长s(1234);
双t(56.78);
std::条件变量cond;
std::互斥m1;
std::互斥体m2;
void func1(){
while(true){
//由于等待解锁互斥锁,因此不需要
//std::this_线程::sleep_for(std::chrono::纳秒(1));
std::唯一锁lck1(m1);
条件等待(lck1);
int n1(n);
长s1(s);
条件等待(lck1);
int n2(n);
长s2(s);
lck1.unlock();
标准:唯一锁lck2(m2);
双ti(t);
lck2.unlock();
//计算并打印一些输出
std::this_thread::sleep_for(std::chrono::毫秒((n1*n2)/2));

std::cout您可以用以下内容代替睡眠:

std::this_thread::yield();
这将使另一个线程有机会获得锁


您可以在不使用条件变量的情况下执行此操作:

long s[2] = {1234,1234}; // instead of a single value


void func1() {
    while (true) {
        std::unique_lock<std::mutex> lck1(m1);
        int n1(n);
        long s1(s[0]);
        long s2(s[1]);
        lck1.unlock();

        int n2 = n1 + 1;
// ...rest of func1 is unchanged...


void func2() {
    while (true) {
        std::unique_lock<std::mutex> lck1(m1);
        n++;
        // compute s[0]
        std::this_thread::sleep_for(std::chrono::milliseconds((n*n)/3));
        n++;
        // compute s[1]
        std::this_thread::sleep_for(std::chrono::milliseconds((n*n)/3));

        std::this_thread::yield();
    }
}
long s[2]={12341234};//而不是单个值
void func1(){
while(true){
std::唯一锁lck1(m1);
int n1(n);
长s1(s[0]);
长s2(s[1]);
lck1.unlock();
int n2=n1+1;
//…func1的其余部分保持不变。。。
void func2(){
while(true){
std::唯一锁lck1(m1);
n++;
//计算s[0]
std::this_thread::sleep_for(std::chrono::毫秒((n*n)/3));
n++;
//计算s[1]
std::this_thread::sleep_for(std::chrono::毫秒((n*n)/3));
std::this_thread::yield();
}
}

首先,您必须假设条件变量
wait
调用实际上并没有等待。一个有效的(尽管是极端的)实现是
lk.unlock();lk.lock();
,有时由于“虚假唤醒”,它的行为确实如此。您确实需要将条件与条件变量关联,并在不满足条件时循环

其次,如果在保持互斥锁的同时通知条件变量,那么等待的线程将从通知中唤醒,只会阻塞互斥锁,因此通知线程可能会在等待的线程获得机会之前重新获取互斥锁

因此,最好在通知条件变量之前解锁互斥锁

lck1.unlock();
cond.notify_all();
这使等待的线程有机会在通知线程重新获得锁之前立即获取互斥锁


您可以添加
std::this_thread::yield()
在迭代之间调用,以使其他线程有机会获得锁。然而,这并不理想——任何必须显式执行某些操作以扰乱调度程序的代码都是重写的目标。

似乎您希望t3触发t1和t2,然后t1和t2触发t3。您可以使用4个互斥体,m1代表t1,m2代表t2,m31和m32代表t3。t1等待m1,完成它的工作并释放m31。t1等待m2,完成它的工作,然后释放m32。t3等待m31,然后m32,完成它的工作,然后释放m1和m2。请发布真实的可构建可运行代码来重现您的问题。阅读关于发布一个。@rcgldr这个想法很好,但它不能确保我得到了两个连续的值。或者可能是我弄错了。@n.m.认为我应该将其减少到最小值,但现在将其更改为可构建和可运行。如果您希望t2恰好触发t1的一次迭代,可以使用两个条件变量来完成。t2表示“嘿,我增加了n”,t1表示“嘿,我推进了一次迭代”.不清楚t3在生活中的目的是什么。它不涉及任何共享资源。您可能应该在示例中添加输出语句,并说明您得到的输出(没有睡眠)你想要得到什么样的输出。阅读规范这正是我需要的,但它在睡眠时不起作用。而且我认为这不会有什么真正的区别,因为函数调用(无论是哪种)需要比实际睡眠时间更长的时间。但这样就永远不可能使它更高效。保证另一个等待线程在相同的时间之前获得锁的东西将是完美的。经过测试,它有非常奇怪的行为。有时它只打印一行(可能永远不会返回func1)或者它只是无休止地打印相同的第一行而不做任何更改(因此可能永远不会回到func2)。此外,它还将我需要关注的所需存储空间增加了一倍,以避免交换速度过快而过慢。感谢虚假唤醒的提示!但在通知之前,我已经解锁了,这完全没有任何区别。