|
20 | 20 | \ref{thread.condition}& Condition variables & \tcode{<condition_variable>} \\ \rowsep
|
21 | 21 | \ref{thread.sema} & Semaphores & \tcode{<semaphore>} \\ \rowsep
|
22 | 22 | \ref{thread.coord} & Coordination types & \tcode{<latch>} \tcode{<barrier>} \\ \rowsep
|
23 |
| -\ref{futures} & Futures & \tcode{<future>} \\ |
| 23 | +\ref{futures} & Futures & \tcode{<future>} \\ \rowsep |
| 24 | +\ref{saferecl} & Safe reclamation & \tcode{<rcu>} \\ |
24 | 25 | \end{libsumtab}
|
25 | 26 |
|
26 | 27 | \rSec1[thread.req]{Requirements}
|
@@ -11661,3 +11662,363 @@
|
11661 | 11662 | \effects
|
11662 | 11663 | As if by \tcode{x.swap(y)}.
|
11663 | 11664 | \end{itemdescr}
|
| 11665 | + |
| 11666 | +\rSec1[saferecl]{Safe reclamation} |
| 11667 | + |
| 11668 | +\rSec2[saferecl.general]{General} |
| 11669 | + |
| 11670 | +\pnum |
| 11671 | +Subclause \ref{saferecl} contains safe-reclamation techniques, which are most |
| 11672 | +frequently used to straightforwardly resolve access-deletion races. |
| 11673 | + |
| 11674 | +\rSec2[saferecl.rcu]{Read-copy update (RCU)} |
| 11675 | + |
| 11676 | +\rSec3[saferecl.rcu.general]{General} |
| 11677 | + |
| 11678 | +\pnum |
| 11679 | +RCU is a synchronization mechanism |
| 11680 | +that can be used for linked data structures |
| 11681 | +that are frequently read, but seldom updated. |
| 11682 | +RCU does not provide mutual exclusion, |
| 11683 | +but instead allows the user to schedule specified actions |
| 11684 | +such as deletion at some later time. |
| 11685 | + |
| 11686 | +\pnum |
| 11687 | +A class type \tcode{T} is \defn{rcu-protectable} |
| 11688 | +if it has exactly one base class of type \tcode{rcu_obj_base<T, D>} |
| 11689 | +for some \tcode{D}, and that base is public and non-virtual, and |
| 11690 | +it has no base classes of type \tcode{rcu_obj_base<X, Y>} |
| 11691 | +for any other combination \tcode{X}, \tcode{Y}. |
| 11692 | +An object is rcu-protectable if it is of rcu-protectable type. |
| 11693 | + |
| 11694 | +\pnum |
| 11695 | +An invocation of \tcode{unlock} $U$ on an \tcode{rcu_domain dom} |
| 11696 | +corresponds to an invocation of \tcode{lock} $L$ on \tcode{dom} |
| 11697 | +if $L$ is sequenced before $U$ and either |
| 11698 | +\begin{itemize} |
| 11699 | +\item |
| 11700 | +no other invocation of \tcode{lock} on \tcode{dom} |
| 11701 | +is sequenced after $L$ and before $U$, or |
| 11702 | +\item |
| 11703 | +every invocation of \tcode{unlock} $U2$ on \tcode{dom} |
| 11704 | +such that $L$ is sequenced before $U2$ and $U2$ is sequenced before $U$ |
| 11705 | +corresponds to an invocation of \tcode{lock} $L2$ on \tcode{dom} |
| 11706 | +such that $L$ is sequenced before $L2$ and $L2$ is sequenced before $U2$. |
| 11707 | +\end{itemize} |
| 11708 | +\begin{note} |
| 11709 | +This pairs nested locks and unlocks on a given domain in each thread. |
| 11710 | +\end{note} |
| 11711 | + |
| 11712 | +\pnum |
| 11713 | +A \defn{region of RCU protection} on a domain \tcode{dom} |
| 11714 | +starts with a \tcode{lock} $L$ on \tcode{dom} and |
| 11715 | +ends with its corresponding \tcode{unlock} $U$. |
| 11716 | + |
| 11717 | +\pnum |
| 11718 | +Given a region of RCU protection $R$ on a domain \tcode{dom} and |
| 11719 | +given an evaluation $E$ that scheduled another evaluation $F$ in \tcode{dom}, |
| 11720 | +if $E$ does not strongly happen before the start of $R$, |
| 11721 | +the end of $R$ strongly happens before evaluating $F$. |
| 11722 | + |
| 11723 | +\pnum |
| 11724 | +The evaluation of a scheduled evaluation is potentially concurrent with |
| 11725 | +any other scheduled evaluation. |
| 11726 | +Each scheduled evaluation is evaluated at most once. |
| 11727 | + |
| 11728 | +\rSec3[rcu.syn]{Header \tcode{<rcu>} synopsis} |
| 11729 | + |
| 11730 | +\indexheader{rcu} |
| 11731 | +\begin{codeblock} |
| 11732 | +namespace std { |
| 11733 | + // \ref{saferecl.rcu.base}, class template \tcode{rcu_obj_base} |
| 11734 | + template<class T, class D = default_delete<T>> class rcu_obj_base; |
| 11735 | + |
| 11736 | + // \ref{saferecl.rcu.domain}, class \tcode{rcu_domain} |
| 11737 | + class rcu_domain; |
| 11738 | + |
| 11739 | + // \ref{saferecl.rcu.domain.func} non-member functions |
| 11740 | + rcu_domain& rcu_default_domain() noexcept; |
| 11741 | + void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11742 | + void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11743 | + template<class T, class D = default_delete<T>> |
| 11744 | + void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); |
| 11745 | +} |
| 11746 | +\end{codeblock} |
| 11747 | + |
| 11748 | +\rSec3[saferecl.rcu.base]{Class template \tcode{rcu_obj_base}} |
| 11749 | + |
| 11750 | +\pnum |
| 11751 | +Objects of type \tcode{T} to be protected by RCU inherit from |
| 11752 | +a specialization \tcode{rcu_obj_base<T, D>} for some \tcode{D}. |
| 11753 | + |
| 11754 | +\begin{codeblock} |
| 11755 | +namespace std { |
| 11756 | + template<class T, class D = default_delete<T>> |
| 11757 | + class rcu_obj_base { |
| 11758 | + public: |
| 11759 | + void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11760 | + protected: |
| 11761 | + rcu_obj_base() = default; |
| 11762 | + rcu_obj_base(const rcu_obj_base&) = default; |
| 11763 | + rcu_obj_base(rcu_obj_base&&) = default; |
| 11764 | + rcu_obj_base& operator=(const rcu_obj_base&) = default; |
| 11765 | + rcu_obj_base& operator=(rcu_obj_base&&) = default; |
| 11766 | + ~rcu_obj_base() = default; |
| 11767 | + private: |
| 11768 | + D @\exposid{deleter}@; // \expos |
| 11769 | + }; |
| 11770 | +} |
| 11771 | +\end{codeblock} |
| 11772 | + |
| 11773 | +\pnum |
| 11774 | +The behavior of a program that adds specializations for \tcode{rcu_obj_base} |
| 11775 | +is undefined. |
| 11776 | + |
| 11777 | +\pnum |
| 11778 | +\tcode{T} may be an incomplete type. |
| 11779 | +It shall be complete before any member of the resulting specialization of |
| 11780 | +\tcode{rcu_obj_base} is referenced. |
| 11781 | + |
| 11782 | +\pnum |
| 11783 | +\tcode{D} shall be a |
| 11784 | +function object type\iref{function.objects} for which, |
| 11785 | +given a value \tcode{d} of type \tcode{D} and |
| 11786 | +a value \tcode{ptr} of type \tcode{T*}, |
| 11787 | +the expression \tcode{d(ptr)} is valid. |
| 11788 | + |
| 11789 | +\pnum |
| 11790 | +\tcode{D} shall meet the requirements for |
| 11791 | +\oldconcept{DefaultConstructible} and \oldconcept{MoveAssignable}. |
| 11792 | + |
| 11793 | +\pnum |
| 11794 | +If \tcode{D} is trivially copyable, |
| 11795 | +all specializations of \tcode{rcu_obj_base<T, D>} are trivially copyable. |
| 11796 | + |
| 11797 | +\begin{itemdecl} |
| 11798 | +void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11799 | +\end{itemdecl} |
| 11800 | + |
| 11801 | +\begin{itemdescr} |
| 11802 | +\pnum |
| 11803 | +\mandates |
| 11804 | +\tcode{T} is an rcu-protectable type. |
| 11805 | + |
| 11806 | +\pnum |
| 11807 | +\expects |
| 11808 | +\tcode{*this} is |
| 11809 | +a base class subobject of an object \tcode{x} of type \tcode{T}. |
| 11810 | +The member function \tcode{rcu_obj_base<T, D>::retire} |
| 11811 | +was not invoked on \tcode{x} before. |
| 11812 | +The assignment to \exposid{deleter} does not exit via an exception. |
| 11813 | + |
| 11814 | +\pnum |
| 11815 | +\effects |
| 11816 | +Evaluates \tcode{\exposid{deleter} = std::move(d)} and |
| 11817 | +schedules the evaluation of |
| 11818 | +the expression \tcode{\exposid{deleter}(\newline addressof(x))} |
| 11819 | +in the domain \tcode{dom}; |
| 11820 | +the behavior is undefined if that evaluation exits via an exception. |
| 11821 | +May invoke scheduled evaluations in \tcode{dom}. |
| 11822 | + |
| 11823 | +\begin{note} |
| 11824 | +If such evaluations acquire resources held across any invocation of |
| 11825 | +\tcode{retire} on \tcode{dom}, deadlock can occur. |
| 11826 | +\end{note} |
| 11827 | +\end{itemdescr} |
| 11828 | + |
| 11829 | +\rSec3[saferecl.rcu.domain]{Class \tcode{rcu_domain}} |
| 11830 | + |
| 11831 | +\rSec4[saferecl.rcu.domain.general]{General} |
| 11832 | + |
| 11833 | +\begin{codeblock} |
| 11834 | +namespace std { |
| 11835 | + class rcu_domain { |
| 11836 | + public: |
| 11837 | + rcu_domain(const rcu_domain&) = delete; |
| 11838 | + rcu_domain& operator=(const rcu_domain&) = delete; |
| 11839 | + |
| 11840 | + void lock() noexcept; |
| 11841 | + bool try_lock() noexcept; |
| 11842 | + void unlock() noexcept; |
| 11843 | + }; |
| 11844 | +} |
| 11845 | +\end{codeblock} |
| 11846 | + |
| 11847 | +\pnum |
| 11848 | +This class meets the requirements of |
| 11849 | +\oldconcept{Lockable}\iref{thread.req.lockable.req} and |
| 11850 | +provides regions of RCU protection. |
| 11851 | +\begin{example} |
| 11852 | +\begin{codeblock} |
| 11853 | +std::scoped_lock<rcu_domain> rlock(rcu_default_domain()); |
| 11854 | +\end{codeblock} |
| 11855 | +\end{example} |
| 11856 | + |
| 11857 | +\pnum |
| 11858 | +The functions \tcode{lock} and \tcode{unlock} establish |
| 11859 | +(possibly nested) regions of RCU protection. |
| 11860 | + |
| 11861 | +\rSec4[saferecl.rcu.domain.members]{Member functions} |
| 11862 | + |
| 11863 | +\indexlibrarymember{lock}{rcu_domain}% |
| 11864 | +\begin{itemdecl} |
| 11865 | +void lock() noexcept; |
| 11866 | +\end{itemdecl} |
| 11867 | + |
| 11868 | +\begin{itemdescr} |
| 11869 | +\pnum |
| 11870 | +\effects |
| 11871 | +Opens a region of RCU protection. |
| 11872 | + |
| 11873 | +\pnum |
| 11874 | +\remarks |
| 11875 | +Calls to \tcode{lock} |
| 11876 | +do not introduce a data race\iref{intro.races} involving \tcode{*this}. |
| 11877 | +\end{itemdescr} |
| 11878 | + |
| 11879 | +\indexlibrarymember{try_lock}{rcu_domain}% |
| 11880 | +\begin{itemdecl} |
| 11881 | +bool try_lock() noexcept; |
| 11882 | +\end{itemdecl} |
| 11883 | + |
| 11884 | +\begin{itemdescr} |
| 11885 | +\pnum |
| 11886 | +\effects |
| 11887 | +Equivalent to \tcode{lock()}. |
| 11888 | + |
| 11889 | +\pnum |
| 11890 | +\returns |
| 11891 | +\tcode{true}. |
| 11892 | +\end{itemdescr} |
| 11893 | + |
| 11894 | +\indexlibrarymember{unlock}{rcu_domain}% |
| 11895 | +\begin{itemdecl} |
| 11896 | +void unlock() noexcept; |
| 11897 | +\end{itemdecl} |
| 11898 | + |
| 11899 | +\begin{itemdescr} |
| 11900 | +\pnum |
| 11901 | +\expects |
| 11902 | +A call to \tcode{lock} |
| 11903 | +that opened an unclosed region of RCU protection |
| 11904 | +is sequenced before the call to \tcode{unlock}. |
| 11905 | + |
| 11906 | +\pnum |
| 11907 | +\effects |
| 11908 | +Closes the unclosed region of RCU protection |
| 11909 | +that was most recently opened. |
| 11910 | +May invoke scheduled evaluations in \tcode{*this}. |
| 11911 | + |
| 11912 | +\pnum |
| 11913 | +\begin{note} |
| 11914 | +If such evaluations acquire resources |
| 11915 | +held across any invocation of \tcode{unlock} on \tcode{*this}, |
| 11916 | +deadlock can occur. |
| 11917 | +\end{note} |
| 11918 | + |
| 11919 | +\pnum |
| 11920 | +\remarks |
| 11921 | +Calls to \tcode{unlock} do not introduce a data race involving \tcode{*this}. |
| 11922 | +\begin{note} |
| 11923 | +Evaluation of scheduled evaluations can still cause a data race. |
| 11924 | +\end{note} |
| 11925 | +\end{itemdescr} |
| 11926 | + |
| 11927 | +\rSec4[saferecl.rcu.domain.func]{Non-member functions} |
| 11928 | + |
| 11929 | +\indexlibraryglobal{rcu_default_domain}% |
| 11930 | +\begin{itemdecl} |
| 11931 | +rcu_domain& rcu_default_domain() noexcept; |
| 11932 | +\end{itemdecl} |
| 11933 | + |
| 11934 | +\begin{itemdescr} |
| 11935 | +\pnum |
| 11936 | +\returns |
| 11937 | +A reference to a static-duration object of type \tcode{rcu_domain}. |
| 11938 | +A reference to the same object is returned every time this function is called. |
| 11939 | +\end{itemdescr} |
| 11940 | + |
| 11941 | +\indexlibraryglobal{rcu_synchronize}% |
| 11942 | +\begin{itemdecl} |
| 11943 | +void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11944 | +\end{itemdecl} |
| 11945 | + |
| 11946 | +\begin{itemdescr} |
| 11947 | +\pnum |
| 11948 | +\effects |
| 11949 | +If the call to \tcode{rcu_synchronize} does not strongly happen before |
| 11950 | +the lock opening an RCU protection region \tcode{R} on \tcode{dom}, |
| 11951 | +blocks until the \tcode{unlock} closing \tcode{R} happens. |
| 11952 | + |
| 11953 | +\pnum |
| 11954 | +\sync |
| 11955 | +The \tcode{unlock} closing \tcode{R} |
| 11956 | +strongly happens before the return from \tcode{rcu_synchronize}. |
| 11957 | +\end{itemdescr} |
| 11958 | + |
| 11959 | +\indexlibraryglobal{rcu_barrier}% |
| 11960 | +\begin{itemdecl} |
| 11961 | +void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept; |
| 11962 | +\end{itemdecl} |
| 11963 | + |
| 11964 | +\begin{itemdescr} |
| 11965 | +\pnum |
| 11966 | +\effects |
| 11967 | +May evaluate any scheduled evaluations in \tcode{dom}. |
| 11968 | +For any evaluation that happens before the call to \tcode{rcu_barrier} and |
| 11969 | +that schedules an evaluation $E$ in \tcode{dom}, |
| 11970 | +blocks until $E$ has been evaluated. |
| 11971 | + |
| 11972 | +\pnum |
| 11973 | +\sync |
| 11974 | +The evaluation of any such $E$ |
| 11975 | +strongly happens before the return from \tcode{rcu_barrier}. |
| 11976 | + |
| 11977 | +\begin{note} |
| 11978 | +A call to \tcode{rcu_barrier} does not imply |
| 11979 | +a call to \tcode{rcu_synchronize} and vice versa. |
| 11980 | +\end{note} |
| 11981 | +\end{itemdescr} |
| 11982 | + |
| 11983 | +\indexlibraryglobal{rcu_retire}% |
| 11984 | +\begin{itemdecl} |
| 11985 | +template<class T, class D = default_delete<T>> |
| 11986 | +void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); |
| 11987 | +\end{itemdecl} |
| 11988 | + |
| 11989 | +\begin{itemdescr} |
| 11990 | +\pnum |
| 11991 | +\mandates |
| 11992 | +\tcode{is_move_constructible_v<D>} is \tcode{true} and |
| 11993 | +the expression \tcode{d(p)} is well-formed. |
| 11994 | + |
| 11995 | +\pnum |
| 11996 | +\expects |
| 11997 | +\tcode{D} meets the \oldconcept{MoveConstructible} and |
| 11998 | +\oldconcept{Destructible} requirements. |
| 11999 | + |
| 12000 | +\pnum |
| 12001 | +\effects |
| 12002 | +May allocate memory. |
| 12003 | +It is unspecified whether the memory allocation |
| 12004 | +is performed by invoking \tcode{\keyword{operator} \keyword{new}}. |
| 12005 | +Initializes an object \tcode{d1} of type \tcode{D} from \tcode{std::move(d)}. |
| 12006 | +Schedules the evaluation of \tcode{d1(p)} in the domain \tcode{dom}; |
| 12007 | +the behavior is undefined if that evaluation exits via an exception. |
| 12008 | +May invoke scheduled evaluations in \tcode{dom}. |
| 12009 | +\begin{note} |
| 12010 | +If \tcode{rcu_retire} exits via an exception, no evaluation |
| 12011 | +is scheduled. |
| 12012 | +\end{note} |
| 12013 | + |
| 12014 | +\pnum |
| 12015 | +\throws |
| 12016 | +\tcode{bad_alloc} or any exception thrown by the initialization of \tcode{d1}. |
| 12017 | + |
| 12018 | +\pnum |
| 12019 | +\begin{note} |
| 12020 | +If scheduled evaluations acquire resources |
| 12021 | +held across any invocation of \tcode{rcu_retire} on \tcode{dom}, |
| 12022 | +deadlock can occur. |
| 12023 | +\end{note} |
| 12024 | +\end{itemdescr} |
0 commit comments