资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

C/C++多线程编程/并发--学习记录-锁(1)-创新互联

多线程/并发核心需要解决的问题就是数据的互斥和同步

在陆河等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都做网站、网站建设 网站设计制作按需开发,公司网站建设,企业网站建设,品牌网站设计,营销型网站,外贸网站建设,陆河网站建设费用合理。

对于多线程处理数据时(通常是共享内存机制实现), 为了避免多个线程同时访问同一个资源, 我们需要添加锁(lock)来实现共享资源互斥访问.

互斥锁(Mutex)/自旋锁(Spin Lock)
  1. 互斥锁(Mutex)/自旋锁(Spin Lock)的区别.
  1. 互斥锁是sleep-waiting, 自旋锁是busy-waiting
  2. 假设我们有一个两个处理器core1和core2计算机,现在在这台计算机上运行的程序中有两个线程:T1和T2分别在处理器core1和core2上运行,两个线程之间共享着一个资源。
    首先我们说明互斥锁的工作原理,互斥锁是是一种sleep-waiting的锁。假设线程T1获取互斥锁并且正在core1上运行时,此时线程T2也想要获取互斥锁(pthread_mutex_lock),但是由于T1正在使用互斥锁使得T2被阻塞。当T2处于阻塞状态时,T2被放入到等待队列中去,处理器core2会去处理其他任务而不必一直等待(忙等)。也就是说处理器不会因为线程阻塞而空闲着,它去处理其他事务去了。
    而自旋锁就不同了,自旋锁是一种busy-waiting的锁。也就是说,如果T1正在使用自旋锁,而T2也去申请这个自旋锁,此时T2肯定得不到这个自旋锁。与互斥锁相反的是,此时运行T2的处理器core2会一直不断地循环检查锁是否可用(自旋锁请求),直到获取到这个自旋锁为止。
    从“自旋锁”的名字也可以看出来,如果一个线程想要获取一个被使用的自旋锁,那么它会一致占用CPU请求这个自旋锁使得CPU不能去做其他的事情,直到获取这个锁为止,这就是“自旋”的含义。
    当发生阻塞时,互斥锁可以让CPU去处理其他的任务;而自旋锁让CPU一直不断循环请求获取这个锁。通过两个含义的对比可以我们知道“自旋锁”是比较耗费CPU的。
C++ 中的线程锁

C++11中提供了std::mutex, 对于多线程加锁操作提供了很好的支持. [mutex: 互斥量]

1. 使用std::mutex. [不推荐]

直接使用mutexlockunlock. 不推荐, 未及时释放锁就会导致死锁, 容易造成死锁现象

#include#include#include#include#include#includeint counter = 0;
std::mutex mtx; // 保护counter
 
void increase(int time) {for (int i = 0; i< time; i++) {mtx.lock();
        // 当前线程休眠1毫秒
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter++;
        mtx.unlock();
    }
}
 
int main(int argc, char** argv) {std::thread t1(increase, 10000);
    std::thread t2(increase, 10000);
    t1.join();
    t2.join();
    std::cout<< "counter:"<< counter<< std::endl;
    return 0;
}
  1. 对于std::mutex对象,任意时刻最多允许一个线程对其进行上锁
  2. mtx.lock():调用该函数的线程尝试加锁。如果上锁不成功,即:其它线程已经上锁且未释放,则当前线程block。如果上锁成功,则执行后面的操作,操作完成后要调用mtx.unlock()释放锁,否则会导致死锁的产生
  3. mtx.unlock():释放锁
  4. std::mutex还有一个操作:mtx.try_lock(),字面意思就是:“尝试上锁”,与mtx.lock()的不同点在于:如果上锁不成功,当前线程不阻塞。
2.std::lock_guard推荐
  1. std::lock_guard只有构造函数和析构函数。简单的来说:当调用构造函数时,会自动调用传入的对象的lock()函数,而当调用析构函数时,自动调用unlock()函数(这就是所谓的RAII)。
  2. RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。
#include#include#include#include#include#includeint counter = 0;
std::mutex mtx; // 保护counter
 
void increase_proxy(int time, int id) {for (int i = 0; i< time; i++) {// std::lock_guard对象构造时,自动调用mtx.lock()进行上锁
        // std::lock_guard对象析构时,自动调用mtx.unlock()释放锁
        std::lock_guardlk(mtx);
        // 线程1上锁成功后,抛出异常:未释放锁
        if (id == 1) {throw std::runtime_error("throw excption....");
        }
        // 当前线程休眠1毫秒
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        counter++;
    }
}
 
void increase(int time, int id) {try {increase_proxy(time, id);
    }
    catch (const std::exception& e){std::cout<< "id:"<< id<< ", "<< e.what()<< std::endl;
    }
}
 
int main(int argc, char** argv) {std::thread t1(increase, 10000, 1);
    std::thread t2(increase, 10000, 2);
    t1.join();
    t2.join();
    std::cout<< "counter:"<< counter<< std::endl;
    return 0;
}

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前文章:C/C++多线程编程/并发--学习记录-锁(1)-创新互联
分享URL:http://cdkjz.cn/article/jogji.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

业务热线:400-028-6601 / 大客户专线   成都:13518219792   座机:028-86922220