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的影响操作该变量。也就是说这个锁毫无用处。