多线程mutex

1.线程不锁,导致最终获取数据不对

int sum = 0;
mutex mu;
void A()
{
    for (int i=0;i<100000;++i)
    {
        sum++;
    }
    cout << "a is :" << sum << endl;
}

int main()
{
    thread a(A);
    thread b(A);
    thread c(A);
    a.join();
    b.join();
    c.join();
   
    cout << "父线程" << endl;
    cout << "a is :" << sum << endl;
    return 0;
}

 2.线程加mutex锁,方法:对数据采用lock()和unlock()方法成对出现

void A()
{
    for (int i=0;i<100000;++i)
    {
        mu.lock();
        sum++;
        mu.unlock();
    }
    cout << "a is :" << sum << endl;
}

3.lock()和unlock(),有两个问题:

1.写两个太麻烦

2.如果在lock过程抛出异常会导致死锁

采用的方法是用lock_guard<mutex>,它会自己解锁。在某个lock_guard对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。

void A()
{
    for (int i=0;i<100000;++i)
    {
        lock_guard<mutex> lockmu(mu);
        sum++;
    }
    cout << "a is :" << sum << endl;
}

 4.当有两个锁锁数据的时候,如果调用顺序不同会产生死锁,在A中顺序是a,b,在B中顺序是b,a

会导致程序死锁。

int sum = 0;
mutex mu;
mutex mu2;
void A()
{
    for (int i=0;i<100000;++i)
    {
        lock_guard<mutex> lockmu(mu);
        sum++;
        lock_guard<mutex> lockmu2(mu2);
        sum++;
    }
    cout << "a is :" << sum << endl;
}

void B()
{
    for (int i = 0; i < 100000; ++i)
    {
        lock_guard<mutex> lockmu2(mu2);
        sum++;
        lock_guard<mutex> lockmu(mu);
        sum++;
    }
    cout << "a is :" << sum << endl;
}

int main()
{
    thread a(A);
    thread b(B); 
    a.join();
    b.join();
  
    cout << "父线程" << endl;
    cout << "a is :" << sum << endl;
    return 0;
}

5.解决的办法是采用lock开始就规定好锁的顺序,并在每个锁中加入adopt_lock适配lock的参数,可以保证锁的顺序。

int sum = 0;
mutex mu;
mutex mu2;
void A()
{
    for (int i=0;i<100000;++i)
    {
        lock(mu, mu2);
        lock_guard<mutex> lockmu(mu,adopt_lock);
        sum++;
        lock_guard<mutex> lockmu2(mu2, adopt_lock);
        sum++;
    }
    cout << "a is :" << sum << endl;
}

void B()
{
    for (int i = 0; i < 100000; ++i)
    {
        lock(mu, mu2);
        lock_guard<mutex> lockmu2(mu2, adopt_lock);
        sum++;
        lock_guard<mutex> lockmu(mu, adopt_lock);
        sum++;
    }
    cout << "a is :" << sum << endl;
}

int main()
{
    thread a(A);
    thread b(B); 
    a.join();
    b.join();
  
    cout << "父线程" << endl;
    cout << "a is :" << sum << endl;
    return 0;
}

 6.和lock_guard相对的还有一个更灵活的锁unique_lock,

unique_lock优点:

1.在lock_guard的范围下,所有代码都被锁住,而unique_lock范围下,如果不加参数(defer_lock),效果如下:

 2.unique_lock可以通过move函数转移控制权,而lock_guard不行。

unique_lock缺点:

消耗更多性能。

7.多线程的call_once的使用

转载:C++11中的std::call_once_爱很遥远-CSDN博客

8.条件变量condition_variable使用

主要要点:在于相当于在全局设置了一个记录器,被触发一次,就会记录一次,然后要用的时候就减一次。

转载:C++-----------notify_one()与notify_all()_1.01的博客-CSDN博客

condition_variable cv;
mutex mu;
vector<int> sum;
void A()
{
    for (int i = 0; i < 10; ++i)
    {
        unique_lock<mutex> locker(mu);
        cv.notify_one();
        sum.emplace_back(i);
        cout << "sum is:" << i << endl;
    }
}

void B()
{
    int data = 0;
    while (data!=9)
    {
        unique_lock<mutex> locker(mu);
        cv.wait(locker, []() {return sum.size()!=0; });
        data = sum[0];
        sum.erase(sum.begin());
        cout << "data is:" << data << endl;
    }
}
int main()
{
    thread a(A);
    thread b(B); 
    a.join();
    b.join();
  
    cout << "父线程" << endl;
    return 0;
}

9.异步线程future和 async、promise

1.std::promise 是C++11并发编程中常用的一个类,常配合std::future使用

在两个线程中,promise  p,future f=p.get_future, 两个线程同时启动,当遇到f.get(),如果另一个线程不给p设置值,f就会一直阻塞,等待,线程p中被设置了值,才继续下去

多线程笔记一 future和async的使用_qq_1410888563的博客-CSDN博客

void A(promise<int> &p)
{
    cout << "1:" << endl;
    p.set_value(10);
    cout << "3:" << endl;
    int a = 20;
    a = a * 10;
    cout << "data is:" <<a << endl;
}

void B(future<int>& f)
{
    cout << "2:" << endl;
    int data =f.get();
    cout << "data is:" << data <<endl;
}

int main()
{
    promise<int> pro;
    future<int> fu = pro.get_future();
    thread a(A,ref(pro));
    thread b(B,ref(fu));
    a.join();
    b.join();
  
    cout << "父线程" << endl;
    return 0;
}

10.packaged-task

主要作用:使代码更加简洁

int A(int a, int& b)
{
    b += 10;
    return a + b;
}
int main()
{
    packaged_task<int(int, int&)> t(A);
    future<int> f = t.get_future();
    int num = 10;
    thread a(move(t),10, ref(num));
    a.join();
    int b= f.get();
    cout << "b is :" <<b<< endl;
    cout << "num is :" << num << endl;
    return 0;
}

 11.时间限制4种类型方法

int main()
{
    thread t(A);
    this_thread::sleep_for(chrono::milliseconds(3));
    chrono::steady_clock::time_point tp = chrono::steady_clock::now() + chrono::microseconds(4);
    this_thread::sleep_until(tp);

    mutex mu;
    unique_lock<mutex> locker(mu);
    locker.try_lock_for(chrono::microseconds(3));
    locker.try_lock_until(tp);

    condition_variable cond;
    cond.wait_for(locker,chrono::microseconds(3));
    cond.wait_until(locker, tp);

    promise<int> p;
    future<int> f = p.get_future();
    f.wait_for(chrono::microseconds(3));
    f.wait_until(tp);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Rust 中,`Arc`、`Mutex` 和 `Option` 都是非常常用的类型,尤其是在多线程编程中。 `Arc` 是一个智能指针类型,它可以在多线程环境中安全地共享数据。`Arc` 的全称是“原子引用计数器”(Atomic Reference Counting),它可以让多个线程同时拥有同一个值的所有权,并且保证所有权的转移是线程安全的。 `Mutex` 是一个互斥体类型,它可以保证在同一时刻只有一个线程能够访问被锁定的数据。在多线程编程中,如果多个线程同时访问同一个变量,就会出现竞争条件(Race Condition),导致程序出错。使用 `Mutex` 可以解决这个问题。 `Option` 是一个枚举类型,它可以表示一个值存在或不存在。在多线程编程中,如果多个线程同时访问同一个变量,就可能会出现空指针异常(Null Pointer Exception)。使用 `Option` 可以明确地表示一个值是否存在,从而避免这个问题。 下面是一个使用这些类型的例子: ```rust use std::sync::{Arc, Mutex}; fn main() { let data = Arc::new(Mutex::new(Some("hello"))); let mut handles = vec![]; for i in 0..10 { let data = data.clone(); let handle = std::thread::spawn(move || { let mut data = data.lock().unwrap(); // 这里使用了 take 方法,将 Option 类型的值取出来并赋值为 None // 这样可以避免多个线程同时访问同一个变量的问题 let value = data.take().unwrap(); println!("Thread {} got value: {}", i, value); }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } } ``` 上面的代码创建了一个共享数据 `data`,它是一个 `Arc<Mutex<Option<&str>>>` 类型。在每个线程中,我们都使用了 `data.lock().unwrap()` 来获取数据的可变引用,并使用了 `take()` 方法将数据取出来。这样所有的线程都可以安全地访问 `data` 的值,而不用担心竞争条件和空指针异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值