ORB-SLAM 关于mutex 锁的理解

Mutex,互斥量,就是互斥访问的量。这种东东只在多线程编程中起作用,在单线程程序中是没有什么用处的。从c++11开始,c++提供了std::mutex类型,对于多线程的加锁操作提供了很好的支持。

在c++等高级编程语言中,锁是用mutex(互斥量)来提供“访问保护”的 ,这个互斥量被不同线程间同时运用,规则为有锁即可运行。如果要执行操作线程间共用的变量的代码段,可以通过加锁去判断该变量是否被其他线程操作,即能拿到锁说明只有该线程申请操作共用变量,拿不到锁则等待。

测试1.1

int counter = 0; // counter
int counter1 = 0;
int counter2 = 0;
std::mutex mtx; 

void increase(int time) {
    {
        //std::this_thread::sleep_for(std::chrono::milliseconds(1));
        mtx.lock();
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter1++;
            counter++;
        }
        mtx.unlock();
    }
    std::cout <<"increase before sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout <<"increase after sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;

}
void thincrease(int time) {
    {
        mtx.lock();
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter2++;
            counter++;
        }
        mtx.unlock();
    }
    std::cout <<"thincrease before sleep  " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout <<"thincrease after sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
}
using namespace std;
using namespace cv;

int main() {
     std::thread t1(increase, 1000);
    std::thread t2(thincrease, 1000);
    t1.join();
    t2.join();
   
    return 0;
}

输出结果

increase before sleep counter:1000  counter1:1000  counter2:0
increase after sleep counter:1917  counter1:1000  counter2:917
thincrease before sleep  counter:2000  counter1:1000  counter2:1000
thincrease after sleep counter:2000  counter1:1000  counter2:1000

测试1.2

int counter = 0; // counter
int counter1 = 0;
int counter2 = 0;
std::mutex mtx; 

void increase(int time) {
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        mtx.lock();
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter1++;
            counter++;
        }
        mtx.unlock();
    }
    std::cout <<"increase before sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout <<"increase after sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;

}
void thincrease(int time) {
    {
        mtx.lock();
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter2++;
            counter++;
        }
        mtx.unlock();
    }
    std::cout <<"thincrease before sleep  " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout <<"thincrease after sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
}
using namespace std;
using namespace cv;

int main() {
     std::thread t1(increase, 1000);
    std::thread t2(thincrease, 1000);
    t1.join();
    t2.join();
   
    return 0;
}

输出结果

thincrease before sleep  counter:1000  counter1:0  counter2:1000
thincrease after sleep counter:1921  counter1:921  counter2:1000
increase before sleep counter:2000  counter1:1000  counter2:1000
increase after sleep counter:2000  counter1:1000  counter2:1000

结论

对比上面两项可以发现,同时用到同一个锁,谁先抢到谁先运行,其余使用这个锁的地方即使运行到此处也需要等待;直到先抢到锁释放锁,后者拿到锁才会运行。

测试2.1

int counter = 0; // counter
int counter1 = 0;
int counter2 = 0;
std::mutex mtx; // 保护counter
void increase(int time) {
    std::cout <<"increase unlock before sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2<< std::endl;
    for (int i = 0; i < time; i++) {
        // 当前线程休眠1毫秒
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter1++;
        counter++;
    }
    std::cout <<"increase unlock end " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
}
void thincrease(int time) {
    {
        mtx.lock();
        std::cout <<"thincrease lock"<< std::endl;
        for (int i = 0; i < time; i++) {
            // 当前线程休眠1毫秒
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter2++;
            counter++;
        }
        mtx.unlock();
        std::cout <<"thincrease unlock before sleep "<< "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2<< std::endl;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout <<"thincrease after sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;

    std::cout <<"thincrease unlock start " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    for (int i = 0; i < time; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter2++;
        counter++;
    }
    std::cout <<"thincrease unlock end " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
}
using namespace std;
using namespace cv;

int main() {
    std::thread t1(increase, 1000);
    std::thread t2(thincrease, 1000);
    t1.join();
    t2.join();
   
    return 0;
}

输出结果

increase unlock before sleep counter:0  counter1:0  counter2:0
thincrease lock
thincrease unlock before sleep counter:1999  counter1:999  counter2:1000
increase unlock end counter:2000  counter1:1000  counter2:1000
thincrease after sleep counter:2000  counter1:1000  counter2:1000
thincrease unlock start counter:2000  counter1:1000  counter2:1000
thincrease unlock end counter:3000  counter1:1000  counter2:2000

 测试2.2

int counter = 0; // counter
int counter1 = 0;
int counter2 = 0;
std::mutex mtx; // 保护counter
void increase(int time) {

    std::cout <<"increase unlock start " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
     for (int i = 0; i < time; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter1++;
        counter++;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    
    std::cout <<"increase unlock end " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
 
    {
        mtx.lock();
        std::cout <<"increase lock"<< std::endl; 
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter1++;
            counter++;
        }
        mtx.unlock();
        std::cout <<"increase unlock before sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2<< std::endl;
    }
}
void thincrease(int time) {

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    std::cout <<"thincrease unlock start " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    for (int i = 0; i < time; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter2++;
        counter++;
    }
    std::cout <<"thincrease unlock end " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
 
    {
        mtx.lock();
        std::cout <<"thincrease lock"<< std::endl;
        for (int i = 0; i < time; i++) {
            // 当前线程休眠1毫秒
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter2++;
            counter++;
        }
        mtx.unlock();
        std::cout <<"thincrease unlock before sleep "<< "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2<< std::endl;
    }

}
using namespace std;
using namespace cv;

int main() {
    std::thread t1(increase, 1000);
    std::thread t2(thincrease, 1000);
    t1.join();
    t2.join();
   
    return 0;
}

输出结果

increase unlock start counter:0  counter1:0  counter2:0
thincrease unlock start counter:931  counter1:931  counter2:0
increase unlock end counter:1998  counter1:1000  counter2:998
increase lock
thincrease unlock end counter:2001  counter1:1001  counter2:1000
increase unlock before sleep counter:3000  counter1:2000  counter2:1000
thincrease lock
thincrease unlock before sleep counter:4000  counter1:2000  counter2:2000

 测试2.3

int counter = 0; // counter
int counter1 = 0;
int counter2 = 0;
std::mutex mtx;

void increase(int time) {

    {
        mtx.lock();
        std::cout <<"increase lock"<< std::endl; 
        for (int i = 0; i < time; i++) {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            counter1++;
            counter++;
        }
        mtx.unlock();
        std::cout <<"increase unlock before sleep " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2<< std::endl;
    }

}
void thincrease(int time) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    std::cout <<"thincrease unlock start " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
    for (int i = 0; i < time; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter2++;
        counter++;
    }
    std::cout <<"thincrease unlock end " << "counter:" << counter << "  counter1:" << counter1 << "  counter2:" << counter2 << std::endl;
}
using namespace std;
using namespace cv;

int main() {
    std::thread t1(increase, 1000);
    std::thread t2(thincrease, 1000);
    t1.join();
    t2.join();
   
    return 0;
}

输出结果

increase lock
thincrease unlock start counter:93  counter1:93  counter2:0
increase unlock before sleep counter:1908  counter1:1000  counter2:908
thincrease unlock end counter:2000  counter1:1000  counter2:1000

结论

对比上面三项可以发现,锁不是对应的变量,而是对应的某个代码段,锁维护的是这个代码段,因为这个代码段涉及到线程间的变量,所以能够维护线程间的变量不会同时被多个线程同时操作。

对涉及操作线程间的变量的代码段加锁,能够保证两个线程不会同时维护和操作相同的变量。

A线程和B线程在维护同一把锁的情况下,当A线程运行到需要操作线程间变量时。如果锁没有被占用,则可以执行锁后续的代码段,直至解锁或者大括号结束自动解锁,此期间线程B是拿不到锁的;如果锁已经被其他线程占用,那么A则会在此处等待,直至其他线程释放该锁。

A线程和B线程都维护同一把锁的情况下,当A线程运行到需要操作线程间变量时。如果锁没有被占用,则可以执行锁后续的代码段,直至解锁或者大括号结束自动解锁,此期间线程B是拿不到锁的;如果锁已经被其他线程占用,那么A则会在此处等待,直至其他线程释放该锁。

如果在A线程维护锁的情况下,而B线程依旧能够操作A线程锁维护的变量,因为B不会受A的影响。也由于B线程不能抢占该锁,A线程同样不受B的影响操作该变量。也就是说这个锁毫无用处。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值