-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[libc++] Implement P0718R2: atomic<shared_ptr<T>>
#78317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Also implemented LWG3661, LWG3893
@llvm/pr-subscribers-libcxx Author: Mital Ashok (MitalAshok) ChangesImplements P0718R2. This is quite a "dumb" implementation: It just reuses the now-deprecated functions in [depr.util.smartptr.shared.atomic] on a held P1644R0 ( I also noticed LWG3661 ( I also added forward declarations for the partial specializations in Patch is 33.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/78317.diff 17 Files Affected:
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 893a3b13ca06e02..ea411ee8d672776 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -180,7 +180,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_atomic_ref`` *unimplemented*
--------------------------------------------------- -----------------
- ``__cpp_lib_atomic_shared_ptr`` *unimplemented*
+ ``__cpp_lib_atomic_shared_ptr`` ``201711L``
--------------------------------------------------- -----------------
``__cpp_lib_atomic_value_initialization`` ``201911L``
--------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 62a1fec627d0ca7..c6efadd4ba1e204 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -60,6 +60,7 @@ Implemented Papers
- P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``)
- P1759R6 - Native handles and file streams
- P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``
+- P0718R2 - Revising ``atomic_shared_ptr`` for C++20
Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index d73088687975c27..eae002a35d33454 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -12,7 +12,7 @@
"`P0600R1 <https://wg21.link/P0600R1>`__","LWG","nodiscard in the Library","Albuquerque","|Complete|","16.0"
"`P0616R0 <https://wg21.link/P0616R0>`__","LWG","de-pessimize legacy <numeric> algorithms with std::move","Albuquerque","|Complete|","12.0"
"`P0653R2 <https://wg21.link/P0653R2>`__","LWG","Utility to convert a pointer to a raw pointer","Albuquerque","|Complete|","6.0"
-"`P0718R2 <https://wg21.link/P0718R2>`__","LWG","Atomic shared_ptr","Albuquerque","",""
+"`P0718R2 <https://wg21.link/P0718R2>`__","LWG","Atomic shared_ptr","Albuquerque","|Complete|","18.0"
"`P0767R1 <https://wg21.link/P0767R1>`__","CWG","Deprecate POD","Albuquerque","|Complete|","7.0"
"`P0768R1 <https://wg21.link/P0768R1>`__","CWG","Library Support for the Spaceship (Comparison) Operator","Albuquerque","|Complete|",""
"`P0777R1 <https://wg21.link/P0777R1>`__","LWG","Treating Unnecessary ``decay``\ ","Albuquerque","|Complete|","7.0"
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index b24ecc5525a1497..597861409039181 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -157,7 +157,7 @@
"`3654 <https://wg21.link/LWG3654>`__","``basic_format_context::arg(size_t)`` should be ``noexcept`` ","February 2022","|Complete|","15.0","|format|"
"`3657 <https://wg21.link/LWG3657>`__","``std::hash<std::filesystem::path>`` is not enabled","February 2022","|Complete|","17.0"
"`3660 <https://wg21.link/LWG3660>`__","``iterator_traits<common_iterator>::pointer`` should conform to §[iterator.traits]","February 2022","|Complete|","14.0","|ranges|"
-"`3661 <https://wg21.link/LWG3661>`__","``constinit atomic<shared_ptr<T>> a(nullptr);`` should work","February 2022","",""
+"`3661 <https://wg21.link/LWG3661>`__","``constinit atomic<shared_ptr<T>> a(nullptr);`` should work","February 2022","|Complete|","18.0"
"","","","","",""
"`3564 <https://wg21.link/LWG3564>`__","``transform_view::iterator<true>::value_type`` and ``iterator_category`` should use ``const F&``","July 2022","","","|ranges|"
"`3617 <https://wg21.link/LWG3617>`__","``function``/``packaged_task`` deduction guides and deducing ``this``","July 2022","",""
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index fe0f13f6e8cb2c2..88a08b01d4982ea 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -3,7 +3,7 @@
"`3884 <https://wg21.link/LWG3884>`__","``flat_foo`` is missing allocator-extended copy/move constructors","Varna June 2023","","","|flat_containers|"
"`3885 <https://wg21.link/LWG3885>`__","``op`` should be in [zombie.names]","Varna June 2023","|Nothing To Do|","",""
"`3887 <https://wg21.link/LWG3887>`__","Version macro for ``allocate_at_least``","Varna June 2023","","",""
-"`3893 <https://wg21.link/LWG3893>`__","LWG 3661 broke ``atomic<shared_ptr<T>> a; a = nullptr;``","Varna June 2023","","",""
+"`3893 <https://wg21.link/LWG3893>`__","LWG 3661 broke ``atomic<shared_ptr<T>> a; a = nullptr;``","Varna June 2023","|Complete|","18.0",""
"`3894 <https://wg21.link/LWG3894>`__","``generator::promise_type::yield_value(ranges::elements_of<Rng, Alloc>)`` should not be ``noexcept``","Varna June 2023","","",""
"`3903 <https://wg21.link/LWG3903>`__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0",""
"`3904 <https://wg21.link/LWG3904>`__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0fe3ab44d2466e9..0fd51788c757148 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -526,6 +526,7 @@ set(files
__memory/allocator_destructor.h
__memory/allocator_traits.h
__memory/assume_aligned.h
+ __memory/atomic_shared_ptr.h
__memory/auto_ptr.h
__memory/builtin_new_allocator.h
__memory/compressed_pair.h
diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 3dfb6937d0325e7..da12b36568fb3be 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -249,6 +249,16 @@ struct atomic<_Tp> : __atomic_base<_Tp> {
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept { return fetch_sub(__op) - __op; }
};
+template <class _Tp>
+class shared_ptr;
+template <class _Tp>
+class weak_ptr;
+
+template <class _Tp>
+struct atomic<shared_ptr<_Tp>>;
+template <class _Tp>
+struct atomic<weak_ptr<_Tp>>;
+
#endif // _LIBCPP_STD_VER >= 20
// atomic_is_lock_free
diff --git a/libcxx/include/__memory/atomic_shared_ptr.h b/libcxx/include/__memory/atomic_shared_ptr.h
new file mode 100644
index 000000000000000..f3fa2260ac91049
--- /dev/null
+++ b/libcxx/include/__memory/atomic_shared_ptr.h
@@ -0,0 +1,233 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MEMORY_ATOMIC_SHARED_PTR_H
+#define _LIBCPP___MEMORY_ATOMIC_SHARED_PTR_H
+
+#include <__memory/addressof.h>
+#include <__memory/shared_ptr.h>
+#include <cstddef>
+#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
+# include <__atomic/memory_order.h>
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+
+class _LIBCPP_EXPORTED_FROM_ABI __sp_mut {
+ void* __lx_;
+
+public:
+ void lock() _NOEXCEPT;
+ void unlock() _NOEXCEPT;
+
+private:
+ _LIBCPP_CONSTEXPR __sp_mut(void*) _NOEXCEPT;
+ __sp_mut(const __sp_mut&);
+ __sp_mut& operator=(const __sp_mut&);
+
+ friend _LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*);
+};
+
+_LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*);
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _Tp __sp_atomic_load(const _Tp* __p) {
+ __sp_mut& __m = std::__get_sp_mut(__p);
+ __m.lock();
+ _Tp __q = *__p;
+ __m.unlock();
+ return __q;
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI void __sp_atomic_store(_Tp* __p, _Tp& __r) {
+ __sp_mut& __m = std::__get_sp_mut(__p);
+ __m.lock();
+ __p->swap(__r);
+ __m.unlock();
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI bool __sp_atomic_compare_exchange_strong(_Tp* __p, _Tp* __v, _Tp& __w) {
+ _Tp __temp;
+ __sp_mut& __m = std::__get_sp_mut(__p);
+ __m.lock();
+ if (__p->__owner_equivalent(*__v)) {
+ std::swap(__temp, *__p);
+ *__p = __w;
+ __m.unlock();
+ return true;
+ }
+ std::swap(__temp, *__v);
+ *__v = *__p;
+ __m.unlock();
+ return false;
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _Tp __sp_atomic_exchange(_Tp* __p, _Tp& __r) {
+ __sp_mut& __m = std::__get_sp_mut(__p);
+ __m.lock();
+ __p->swap(__r);
+ __m.unlock();
+ return __r;
+}
+
+# if _LIBCPP_STD_VER >= 20
+template <class _Tp>
+struct atomic;
+
+template <class _Tp>
+struct __sp_atomic_base {
+ using value_type = _Tp;
+
+ static constexpr bool is_always_lock_free = false;
+ _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return false; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __sp_atomic_base() noexcept = default;
+ _LIBCPP_HIDE_FROM_ABI __sp_atomic_base(_Tp&& __d) noexcept : __p(std::move(__d)) {}
+ _LIBCPP_HIDE_FROM_ABI __sp_atomic_base(const __sp_atomic_base&) = delete;
+ _LIBCPP_HIDE_FROM_ABI void operator=(const __sp_atomic_base&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order = memory_order_seq_cst) noexcept {
+ return std::__sp_atomic_load(std::addressof(__p));
+ }
+ _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); }
+ _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order = memory_order_seq_cst) noexcept {
+ std::__sp_atomic_store(std::addressof(__p), __d);
+ }
+ _LIBCPP_HIDE_FROM_ABI void operator=(_Tp __d) noexcept { std::__sp_atomic_store(std::addressof(__p), __d); }
+ _LIBCPP_HIDE_FROM_ABI void operator=(nullptr_t) noexcept { store(nullptr); }
+
+ _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order = memory_order_seq_cst) noexcept {
+ return std::__sp_atomic_exchange(std::addressof(__p), __d);
+ }
+ _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order, memory_order) noexcept {
+ return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d);
+ }
+ _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order, memory_order) noexcept {
+ return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d);
+ }
+ _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order = memory_order_seq_cst) noexcept {
+ return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d);
+ }
+ _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order = memory_order_seq_cst) noexcept {
+ return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d);
+ }
+
+ // P1644R0 not implemented
+ // void wait(_Tp old, memory_order order = memory_order::seq_cst) const noexcept;
+ // void notify_one() noexcept;
+ // void notify_all() noexcept;
+
+private:
+ _Tp __p;
+};
+
+template <class _Tp>
+struct atomic<shared_ptr<_Tp>> : __sp_atomic_base<shared_ptr<_Tp>> {
+ _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr atomic(nullptr_t) noexcept : atomic() {}
+ _LIBCPP_HIDE_FROM_ABI atomic(shared_ptr<_Tp> desired) noexcept
+ : __sp_atomic_base<shared_ptr<_Tp>>(std::move(desired)) {}
+ _LIBCPP_HIDE_FROM_ABI atomic(const atomic&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI void operator=(const atomic&) = delete;
+ using __sp_atomic_base<shared_ptr<_Tp>>::operator=;
+};
+
+template <class _Tp>
+struct atomic<weak_ptr<_Tp>> : __sp_atomic_base<weak_ptr<_Tp>> {
+ _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr atomic(nullptr_t) noexcept : atomic() {}
+ _LIBCPP_HIDE_FROM_ABI atomic(weak_ptr<_Tp> desired) noexcept : __sp_atomic_base<weak_ptr<_Tp>>(std::move(desired)) {}
+ _LIBCPP_HIDE_FROM_ABI atomic(const atomic&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI void operator=(const atomic&) = delete;
+ using __sp_atomic_base<weak_ptr<_Tp>>::operator=;
+};
+# endif // _LIBCPP_STD_VER >= 20
+
+// [depr.util.smartptr.shared.atomic]
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const shared_ptr<_Tp>*) {
+ return false;
+}
+
+template <class _Tp>
+_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>
+atomic_load(const shared_ptr<_Tp>* __p) {
+ return std::__sp_atomic_load(__p);
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>
+atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) {
+ return std::atomic_load(__p);
+}
+
+template <class _Tp>
+_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) {
+ std::__sp_atomic_store(__p, __r);
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void
+atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) {
+ std::atomic_store(__p, __r);
+}
+
+template <class _Tp>
+_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>
+atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) {
+ return std::__sp_atomic_exchange(__p, __r);
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>
+atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) {
+ return std::atomic_exchange(__p, std::move(__r));
+}
+
+template <class _Tp>
+_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool
+atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) {
+ return std::__sp_atomic_compare_exchange_strong(__p, __v, __w);
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool
+atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) {
+ return std::atomic_compare_exchange_strong(__p, __v, std::move(__w));
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit(
+ shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) {
+ return std::atomic_compare_exchange_strong(__p, __v, std::move(__w));
+}
+
+template <class _Tp>
+inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit(
+ shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) {
+ return std::atomic_compare_exchange_weak(__p, __v, std::move(__w));
+}
+
+#endif // !defined(_LIBCPP_HAS_NO_THREADS)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // LLVM_ATOMIC_ATOMIC_SHARED_PTR_H
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 9a73d439306d9e0..c2a6953382dcd32 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -1556,110 +1556,6 @@ template <class _CharT, class _Traits, class _Yp>
inline _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p);
-#if !defined(_LIBCPP_HAS_NO_THREADS)
-
-class _LIBCPP_EXPORTED_FROM_ABI __sp_mut {
- void* __lx_;
-
-public:
- void lock() _NOEXCEPT;
- void unlock() _NOEXCEPT;
-
-private:
- _LIBCPP_CONSTEXPR __sp_mut(void*) _NOEXCEPT;
- __sp_mut(const __sp_mut&);
- __sp_mut& operator=(const __sp_mut&);
-
- friend _LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*);
-};
-
-_LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*);
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const shared_ptr<_Tp>*) {
- return false;
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_load(const shared_ptr<_Tp>* __p) {
- __sp_mut& __m = std::__get_sp_mut(__p);
- __m.lock();
- shared_ptr<_Tp> __q = *__p;
- __m.unlock();
- return __q;
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) {
- return std::atomic_load(__p);
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI void atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) {
- __sp_mut& __m = std::__get_sp_mut(__p);
- __m.lock();
- __p->swap(__r);
- __m.unlock();
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI void atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) {
- std::atomic_store(__p, __r);
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) {
- __sp_mut& __m = std::__get_sp_mut(__p);
- __m.lock();
- __p->swap(__r);
- __m.unlock();
- return __r;
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>
-atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) {
- return std::atomic_exchange(__p, __r);
-}
-
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI bool
-atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) {
- shared_ptr<_Tp> __temp;
- __sp_mut& __m = std::__get_sp_mut(__p);
- __m.lock();
- if (__p->__owner_equivalent(*__v)) {
- std::swap(__temp, *__p);
- *__p = __w;
- __m.unlock();
- return true;
- }
- std::swap(__temp, *__v);
- *__v = *__p;
- __m.unlock();
- return false;
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI bool
-atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) {
- return std::atomic_compare_exchange_strong(__p, __v, __w);
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit(
- shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) {
- return std::atomic_compare_exchange_strong(__p, __v, __w);
-}
-
-template <class _Tp>
-inline _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit(
- shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) {
- return std::atomic_compare_exchange_weak(__p, __v, __w);
-}
-
-#endif // !defined(_LIBCPP_HAS_NO_THREADS)
-
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MEMORY_SHARED_PTR_H
diff --git a/libcxx/include/memory b/libcxx/include/memory
index ee245d5fd2dcb2e..6c0ec59119f6d20 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -831,29 +831,29 @@ public:
};
template<class T>
- bool atomic_is_lock_free(const shared_ptr<T>* p);
+ bool atomic_is_lock_free(const shared_ptr<T>* p); // Deprecated in C++20
template<class T>
- shared_ptr<T> atomic_load(const shared_ptr<T>* p);
+ shared_ptr<T> atomic_load(const shared_ptr<T>* p); // Deprecated in C++20
template<class T>
- shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);
+ shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo); // Deprecated in C++20
template<class T>
- void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
+ void atomic_store(shared_ptr<T>* p, shared_ptr<T> r); // Deprecated in C++20
template<class T>
- void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
+ void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo); // Deprecated in C++20
template<class T>
- shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
+ shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r); // Deprecated in C++20
template<class T>
shared_ptr<T>
- atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
+ atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo); // Deprecated in C++20
template<class T>
bool
- atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
+ atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w); // Deprecated in C++20
template<class T>
bool
- atomic_compare_exchange_strong( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
+ atomic_compare_exchange_strong( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w); ...
[truncated]
|
Thanks for your contribution!
Can you provide information why using deprecated features is the way to go? It seems likely these functions will be removed in C++26. Per P2863R3 Review Annex D for C++26 (Alisdair Meredith) See paper [P2869] for a more detailed discussion and proposed wording. Polled after discussion of the header compatibility concern: Poll: Remove deprecated shared_ptr atomic access APIs from C++26, with any of the library options listed in P2689? SF F N A SA Consensus to move this paper to LEWG to resolve the header design issue, and then continue on to LWG. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say we should take the opportunity to try implementing it in a lock-free way
// P1644R0 not implemented | ||
// void wait(_Tp old, memory_order order = memory_order::seq_cst) const noexcept; | ||
// void notify_one() noexcept; | ||
// void notify_all() noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these implementable given that you are just storing a shared_ptr
?
I would be OK with using this implementation strategy as a stepping stone for a lockfree implementation, which would require making this experimental before we commit to an ABI. I agree with @huixie90 that we need to implement this in a lockfree way, and my understanding is that this requires more research cause there is no efficient and publicly available implementation that works on all platforms. |
@timuraudio Do you have thoughts about how we could implement this lockfree? |
template <class _Tp> | ||
struct atomic<weak_ptr<_Tp>> : __sp_atomic_base<weak_ptr<_Tp>> { | ||
_LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default; | ||
_LIBCPP_HIDE_FROM_ABI constexpr atomic(nullptr_t) noexcept : atomic() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason was said in LWG3611:
There is no need to also change
atomic<weak_ptr<T>>
becauseweak_ptr
doesn't have a constructor takingnullptr
.
Did you submit an LWG issue for corresponding change of atomic<weak_ptr<T>>
?
_LIBCPP_HIDE_FROM_ABI atomic(weak_ptr<_Tp> desired) noexcept : __sp_atomic_base<weak_ptr<_Tp>>(std::move(desired)) {} | ||
_LIBCPP_HIDE_FROM_ABI atomic(const atomic&) = delete; | ||
|
||
_LIBCPP_HIDE_FROM_ABI void operator=(const atomic&) = delete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment was marked as resolved.
This comment was marked as resolved.
@MitalAshok Is there any progress on this? |
@Zingam It appears that a completely different implementation needs to be used for this to be able to efficiently implement |
Implements P0718R2.
This is quite a "dumb" implementation: It just reuses the now-deprecated functions in [depr.util.smartptr.shared.atomic] on a held
std::{shared/weak}_ptr<T>
member.P1644R0 (
wait
/notify
foratomic<shared_ptr<T>>
) is not implemented. I will work on a subsequent patch, but we needatomic<shared_ptr>
first.I also noticed LWG3661 (
constinit atomic<shared_ptr<T>> a(nullptr);
) did not apply toatomic<weak_ptr<T>>
, but I see no reason not to support it.I also added forward declarations for the partial specializations in
<atomic>
. This shouldn't change the correctness of any code but should give a better error (thatatomic<shared_ptr<T>>
is incomplete, not thatshared_ptr<T>
is a non-trivial type in the primary template)