# std::atomic_fetch_or, std::atomic_fetch_or_explicit

< cpp‎ | atomic

定义于头文件 `<atomic>` |  |
| (1) | (C++11 起)
template< class T > T atomic_fetch_or( std::atomic<T>* obj, typename std::atomic<T>::value_type arg ) noexcept; |  |
template< class T > T atomic_fetch_or( volatile std::atomic<T>* obj, typename std::atomic<T>::value_type arg ) noexcept; |  |
| (2) | (C++11 起)
template< class T > T atomic_fetch_or_explicit( std::atomic<T>* obj, typename std::atomic<T>::value_type arg, std::memory_order order) noexcept; |  |
template< class T > T atomic_fetch_or_explicit( volatile std::atomic<T>* obj, typename std::atomic<T>::value_type arg, std::memory_order order) noexcept; |  |

原子地以 `obj` 的旧值和 `arg` 逐位或的结果替换 `obj` 所指向的值。返回 `obj` 先前保有的值。

如同执行下列内容一般进行运算：

1) obj->fetch_or(arg)
2) obj->fetch_or(arg, order)

若 `std::atomic<T>` 无 `fetch_or` 成员（此成员仅对整数类型提供），则程序为病式。

### 参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要与原子对象中的值逐位或的值
order | - | 此操作所用的内存同步顺序：容许所有值。

### 返回值

`*obj` 的修改顺序中立即前趋此函数效果的值。

### 可能的实现

    template< class T >
    T atomic_fetch_or( std::atomic<T>* obj, typename std::atomic<T>::value_type  arg )
    {
        return obj->fetch_or(arg);
    }

### 示例

    #include <iostream>
    #include <atomic>
    #include <thread>
    #include <chrono>
    #include <functional>

    // 仅为演示目的的二元信号量
    // 此乃简单却有意义的示例：若无线程则原子操作为不必要。
    class Semaphore {
        std::atomic_char m_signaled;
      public:
        Semaphore(bool initial = false)
        {
            m_signaled = initial;
        }
        // 阻塞直至信号量被发信
        void take()
        {
            while (!std::atomic_fetch_and(&m_signaled, false)) {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
        }

        void put()
        {
            std::atomic_fetch_or(&m_signaled, true);
        }
    };

    class ThreadedCounter {
        static const int N = 100;
        static const int REPORT_INTERVAL = 10;
        int m_count;
        bool m_done;
        Semaphore m_count_sem;
        Semaphore m_print_sem;

        void count_up()
        {
            for (m_count = 1; m_count <= N; m_count++) {
                if (m_count % REPORT_INTERVAL == 0) {
                    if (m_count == N) m_done = true;
                    m_print_sem.put(); // 对打印发信，使之发生
                    m_count_sem.take(); // 等待直至打印完成进展
                }
            }
            std::cout << "count_up() done\n";
            m_done = true;
            m_print_sem.put();
        }

        void print_count()
        {
            do {
                m_print_sem.take();
                std::cout << m_count << '\n';
                m_count_sem.put();
            } while (!m_done);
            std::cout << "print_count() done\n";
        }

      public:
        ThreadedCounter() : m_done(false) {}
        void run()
        {
            auto print_thread = std::thread(&ThreadedCounter::print_count, this);
            auto count_thread = std::thread(&ThreadedCounter::count_up, this);
            print_thread.join();
            count_thread.join();
        }
    };

    int main()
    {
        ThreadedCounter m_counter;
        m_counter.run();
    }

输出：

    10
    20
    30
    40
    50
    60
    70
    80
    90
    100
    print_count() done
    count_up() done

### 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
--- | --- | --- | ---
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 `T` | 仅从 `atomic` 参数推导 `T`

### 参阅

fetch_or | 原子地进行参数和原子对象的值的逐位或，并获得先前保有的值 (`std::atomic<T>` 的公开成员函数)
atomic_fetch_and atomic_fetch_and_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值 (函数模板)
atomic_fetch_xor atomic_fetch_xor_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值 (函数模板)