2022-09-01 C++并发编程(十七)

本文详细介绍了C++中std::atomic指针类的使用,包括初始化、判断无锁结构、读写操作、交换更新、比较替换更新以及算数运算。通过实例代码展示了各种操作,帮助开发者掌握在并发环境下如何安全地操作指针。
摘要由CSDN通过智能技术生成


前言

std::atomic<Ptr*> 是原子指针类,除了和原子布尔类相同的成员函数,还有更多的计算相关函数,如果对前两篇文章完全掌握,此篇文章的内容不难掌握。


一、操作std::atomic<Ptr*>类对象

与原子布尔类一样,原子指针类可用普通的类型指针进行初始化:

    char charArr[] = "abcd";

    //初始化原子指针
    std::atomic<char *> atomicPtr(charArr);

判断是否无锁结构:

    //原子指针是否是无锁结构
    std::cout << atomicPtr.is_lock_free() << std::endl;

原子指针值的读取与写入:

    //读取原子指针值,可用读操作的内存次序
    auto charPtr = atomicPtr.load();

    char charArr2[] = "efgh";

    //写入原子指针,可用写操作的内存次序
    atomicPtr.store(charArr2);

原子指针值的交换更新:

    //更新原子指针,返回原值,读改写内存次序
    charPtr = atomicPtr.exchange(charArr);

原子指针值的 “比较替换更新”:

    char *charPtr2 = charArr2;

    char charArr3[] = "ijkl";

    //第一个参数必须是指针,不能是数组,因参数是引用,不会退化成指针
    //依然是两个内存操作次序,与期望指针值一致,则是读改写次序,否则是读次序
    while (!atomicPtr.compare_exchange_weak(charPtr2, charArr3))
    {
    }
    //同 weak 版本,第一个参数必须是指针
    //依然是两个内存操作次序
    atomicPtr.compare_exchange_strong(charPtr2, charArr);

原子指针增加了算数函数,

后移 fetch_add(ptrdiff_t __op, std::memory_order __m = memory_order_seq_cst)

前移fetch_sub(ptrdiff_t __op, std::memory_order __m = memory_order_seq_cst)

其语义是返回原值,指针前后移动若干,可按照 “读改写” 操作设置内存顺序。

    //返回指针原值,原子指针向后移动一个,读改写操作,可用任何内存次序
    charPtr = atomicPtr.fetch_add(1);

    //返回指针原值,原子指针向前移动一个,读改写操作,可用任何内存次序
    charPtr = atomicPtr.fetch_sub(1);

原子指针类还有自增 “++”,自减 “–” 操作,和普通指针运算操作无异,因原子指针类不支持拷贝赋值,只会返回普通指针,并且不可设置内存次序。

    //原子指针向后移动一个,并返回更新的值,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = ++atomicPtr;

    //原子指针向前移动一个,并返回更新的值,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = --atomicPtr;

    //返回指针原值,原子指针后移一个,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = atomicPtr++;

    //返回指针原值,原子指针前移一个,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = atomicPtr--;

    //原子指针像后移动一个,不可设定内存次序,服从std::memory_order_seq_cst
    atomicPtr += 1;

    //原子指针向前移动一个,不可设定内存次序,服从std::memory_order_seq_cst
    atomicPtr -= 1;

以下是全部示例代码,可一边 debug 一边熟悉其操作。

#include <atomic>
#include <iostream>

auto main() -> int
{
    char charArr[] = "abcd";

    //初始化原子指针
    std::atomic<char *> atomicPtr(charArr);

    //原子指针是否是无锁结构
    std::cout << atomicPtr.is_lock_free() << std::endl;

    //读取原子指针值,可用读操作的内存次序
    auto charPtr = atomicPtr.load();

    char charArr2[] = "efgh";

    //写入原子指针,可用写操作的内存次序
    atomicPtr.store(charArr2);

    //更新原子指针,返回原值,读改写内存次序
    charPtr = atomicPtr.exchange(charArr);

    char *charPtr2 = charArr2;

    char charArr3[] = "ijkl";

    //第一个参数必须是指针,不能是数组,因参数是引用,不会退化成指针
    //依然是两个内存操作次序
    while (!atomicPtr.compare_exchange_weak(charPtr2, charArr3))
    {
    }
    //同 weak 版本,第一个参数必须是指针
    //依然是两个内存操作次序
    atomicPtr.compare_exchange_strong(charPtr2, charArr);

    //返回指针原值,原子指针向后移动一个,读改写操作,可用任何内存次序
    charPtr = atomicPtr.fetch_add(1);

    //返回指针原值,原子指针向前移动一个,读改写操作,可用任何内存次序
    charPtr = atomicPtr.fetch_sub(1);

    //原子指针向后移动一个,并返回更新的值,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = ++atomicPtr;

    //原子指针向前移动一个,并返回更新的值,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = --atomicPtr;

    //返回指针原值,原子指针后移一个,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = atomicPtr++;

    //返回指针原值,原子指针前移一个,不可设定内存次序,服从std::memory_order_seq_cst
    charPtr = atomicPtr--;

    //原子指针像后移动一个,不可设定内存次序,服从std::memory_order_seq_cst
    atomicPtr += 1;

    //原子指针向前移动一个,不可设定内存次序,服从std::memory_order_seq_cst
    atomicPtr -= 1;

    return 0;
}

总结

原子指针类相较原子布尔类,增加了一些运算操作,及重载运算符,不难理解,多用即会。

C++ 并发 C++11 C++17 I encountered the concept of multithreaded code while working at my first job after I left college. We were writing a data processing application that had to populate a database with incoming data records. There was a lot of data, but each record was independent and required a reasonable amount of processing before it could be inserted into the database. To take full advantage of the power of our 10-CPU UltraSPARC, we ran the code in multiple threads, each thread processing its own set of incoming records. We wrote the code in C++, using POSIX threads, and made a fair number of mistakes—multithreading was new to all of us—but we got there in the end. It was also while working on this project that I first became aware of the C++ Standards Committee and the freshly published C++ Standard. I have had a keen interest in multithreading and concurrency ever since. Where others saw it as difficult, complex, and a source of problems, I saw it as a powerful tool that could enable your code to take advantage of the available hardware to run faster. Later on I would learn how it could be used to improve the responsiveness and performance of applications even on single-core hardware, by using multiple threads to hide the latency of time-consuming operations such as I/O. I also learned how it worked at the OS level and how Intel CPUs handled task switching. Meanwhile, my interest in C++ brought me in contact with the ACCU and then the C++ Standards panel at BSI, as well as Boost. I followed the initial development of the Boost Thread Library with interest, and when it was abandoned by the original developer, I jumped at the chance to get involved. I have been the primary developer and maintainer of the Boost Thread Library ever since.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停感叹的老林_<C 语言编程核心突破>

不打赏的人, 看完也学不会.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值