Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@
#define @\defnlibxname{cpp_lib_syncbuf}@ 201803L // also in \libheader{iosfwd}, \libheader{syncstream}
#define @\defnlibxname{cpp_lib_task}@ 202506L // also in \libheader{execution}
#define @\defnlibxname{cpp_lib_text_encoding}@ 202306L // also in \libheader{text_encoding}
#define @\defnlibxname{cpp_lib_thread_attributes}@ 202606L // also in \libheader{thread}
#define @\defnlibxname{cpp_lib_three_way_comparison}@ 201907L // freestanding, also in \libheader{compare}
#define @\defnlibxname{cpp_lib_to_address}@ 201711L // freestanding, also in \libheader{memory}
#define @\defnlibxname{cpp_lib_to_array}@ 201907L // freestanding, also in \libheader{array}
Expand Down
199 changes: 187 additions & 12 deletions source/threads.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,13 @@
public:
// \ref{thread.thread.id}, class \tcode{thread::id}
class id;

// \ref{thread.attributes}, thread attributes
template<@\libconcept{same_as}@<char> T> class name_hint;
template<class T> name_hint(const T*) -> name_hint<T>;
template<class T> name_hint(basic_string<T>) -> name_hint<T>;
class stack_size_hint;

using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native}

// construct/copy/destroy
Expand All @@ -1499,6 +1506,98 @@
}
\end{codeblock}

\rSec3[thread.attributes]{Thread attributes}

\pnum
\defnx{thread attribute}{Thread attributes}
can be used to define additional implementation-defined behaviors
on a \tcode{thread} or \tcode{jthread} object.

\pnum
The set of \defnadj{thread attribute}{types} contains
\tcode{thread::name_hint},
\tcode{thread::stack_size_hint}, and
an \impldef{set of additional thread-attributes} set of additional thread-attributes.

\pnum
When an object of a thread attribute type is passed to
a \tcode{thread} or \tcode{jthread} constructor,
it may affect the new thread's behavior.

\indexlibraryglobal{thread::name_hint}%
\begin{codeblock}
template<@\libconcept{same_as}@<char> T>
class thread::name_hint {
public:
constexpr explicit name_hint(basic_string_view<T> n) noexcept;
name_hint(name_hint&&) = delete;
name_hint(const name_hint&) = delete;
private:
basic_string_view<T> @\exposid{name}@; // \expos

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rename this to name_, possibly in a follow-up commit or PR. Same for (size ->) size_.

};
\end{codeblock}

\pnum
The \tcode{name_hint} thread attribute can be used to set the name of a thread
for debugging purposes or platform-specific display mechanisms.

\recommended
Implementations should not store the value of the \tcode{name_hint} attribute
in the \tcode{thread} or \tcode{jthread} object.

\recommended
%FIXME: ordinary literal encoding? Literal encoding of T? What is "THE literal encoding"?
\exposid{name} is interpreted as a string in the literal encoding.
Comment on lines +1549 to +1550

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this moment, I believe the literal encoding must be the ordinary literal encoding because T must be char. I wish we don't need a follow-up LWG issue for this.

Suggested change
%FIXME: ordinary literal encoding? Literal encoding of T? What is "THE literal encoding"?
\exposid{name} is interpreted as a string in the literal encoding.
\exposid{name} is interpreted as a string in the ordinary literal encoding.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point it cannot be anything else, yeah. I'm wondering in which direction we want to resolve this though, and that depends on how likely support for more character types is in the future.

If we say "ordinary literal encoding" now, we will need to change that wording if more support is added.


\indexlibraryctor{thread::name_hint}%
\begin{itemdecl}
constexpr explicit name_hint(basic_string_view<T> n) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{name} with \tcode{n}.
\end{itemdescr}

\indexlibraryglobal{thread::stack_size_hint}%
\begin{codeblock}
namespace std {
class thread::stack_size_hint {
public:
constexpr explicit stack_size_hint(size_t s) noexcept;
private:
size_t @\exposid{size}@; // \expos
};
}
\end{codeblock}

\pnum
\tcode{stack_size_hint} can be used to configure a desired size in bytes
for platform-specific storage required for a thread.
\begin{note}
Such storage is typically used for variables with automatic storage duration.
\end{note}

\pnum
The stack size set by the implementation may be adjusted up or down
to meet platform-specific requirements.

\pnum
If \exposid{size} is zero,
the thread attribute is ignored.

\indexlibraryctor{thread::stack_size_hint}%
\begin{itemdecl}
constexpr explicit stack_size_hint(size_t s) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{size} with \tcode{s}.
\end{itemdescr}

\rSec3[thread.thread.id]{Class \tcode{thread::id}}

\indexlibraryglobal{thread::id}%
Expand Down Expand Up @@ -1675,29 +1774,64 @@

\indexlibraryctor{thread}%
\begin{itemdecl}
template<class F, class... Args> explicit thread(F&& f, Args&&... args);
template<class... Args> explicit thread(Args&&... args);
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\tcode{remove_cvref_t<F>} is not the same type as \tcode{thread}.
\begin{itemize}
\item
\tcode{Args} is not an empty pack, and
\item
\tcode{remove_cvref_t<F Args...[0]>} is not the same type as \tcode{thread}.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
\tcode{remove_cvref_t<F Args...[0]>} is not the same type as \tcode{thread}.
\tcode{remove_cvref_t<Args...[0]>} is not the same type as \tcode{thread}.

\end{itemize}

\pnum
\begin{itemize}
\item
Let $i$ be the smallest value such that
\tcode{decay_t<Args...[$i$]>}
is not a thread attribute type.
If no such $i$ exists, the program is ill-formed.
\item
Let \tcode{F} be \tcode{Args...[$i$]}.
\item
Let \tcode{f} be \tcode{args...[$i$]}.
\item
Let \tcode{Attrs} be a pack of the types
\tcode{Args...[$j$]} for each $j$
such that $0 \leq j < i$.
\item
Let \tcode{attrs} be a pack of the expressions
\tcode{args...[$j$]} for each $j$
such that $0 \leq j < i$.
\item
Let \tcode{FArgs} be a pack of the types
\tcode{Args...[$j$]} for each $j$
such that $i < j < \tcode{sizeof...(args)}$.
\item
Let \tcode{fargs} be a pack of the expressions
\tcode{args...[$j$]} for each $j$
such that $i < j < \tcode{sizeof...(args)}$.
\end{itemize}

\pnum
\mandates
The following are all \tcode{true}:
\begin{itemize}
\item \tcode{is_constructible_v<decay_t<F>, F>},
\item \tcode{(is_constructible_v<decay_t<Args>, Args> \&\& ...)}, and
\item \tcode{is_invocable_v<decay_t<F>, decay_t<Args>...>}.
\item \tcode{(is_constructible_v<decay_t<FArgs>, FArgs> \&\& ...)},
\item \tcode{is_invocable_v<decay_t<F>, decay_t<FArgs>...>}, and
\item No type is present more than once in the pack \tcode{remove_cvref_t<Attrs>}.
\end{itemize}

\pnum
\effects
The new thread of execution executes
\begin{codeblock}
invoke(auto(std::forward<F>(f)), // for \tcode{invoke}, see \ref{func.invoke}
auto(std::forward<Args>(args))...)
auto(std::forward<FArgs>(fargs))...)
\end{codeblock}
with the values produced by \tcode{auto}
being materialized\iref{conv.rval} in the constructing thread.
Expand All @@ -1708,6 +1842,8 @@
\end{note}
If the invocation of \tcode{invoke} terminates with an uncaught exception,
\tcode{terminate} is invoked\iref{except.terminate}.
The parameters \tcode{attrs...}
can affect the behavior of the new thread\iref{thread.attributes}.

\pnum
\sync
Expand Down Expand Up @@ -1951,9 +2087,12 @@
using id = thread::id;
using native_handle_type = thread::native_handle_type;

template<class T> using name_hint = thread::name_hint<T>;
using stack_size_hint = thread::stack_size_hint;

// \ref{thread.jthread.cons}, constructors, move, and assignment
jthread() noexcept;
template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
template<class... Args> explicit jthread(Args&&... args);
~jthread();
jthread(const jthread&) = delete;
jthread(jthread&&) noexcept;
Expand Down Expand Up @@ -2006,21 +2145,52 @@

\indexlibraryctor{jthread}%
\begin{itemdecl}
template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
template<class... Args> explicit jthread(Args&&... args);
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\tcode{remove_cvref_t<F>} is not the same type as \tcode{jthread}.
\tcode{Args} is not an empty pack, and
\tcode{remove_cvref_t<F Args...[0]>} is not the same type as \tcode{jthread}.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
\tcode{remove_cvref_t<F Args...[0]>} is not the same type as \tcode{jthread}.
\tcode{remove_cvref_t<Args...[0]>} is not the same type as \tcode{jthread}.


\pnum
\begin{itemize}
\item
Let $i$ be the smallest value such that
\tcode{decay_t<Args...[$i$]>}
is not a thread attribute type.
If no such $i$ exists, the program is ill-formed.
\item
Let \tcode{F} be \tcode{Args...[$i$]}.
\item
Let \tcode{f} be \tcode{args...[$i$]}.
\item
Let \tcode{Attrs} be a pack of the types
\tcode{Args...[$j$]} for each $j$
such that $0 \leq j < i$.
\item
Let \tcode{attrs} be a pack of the expressions
\tcode{args...[$j$]} for each $j$
such that $0 \leq j < i$.
\item
Let \tcode{FArgs} be a pack of the types
\tcode{Args...[$j$]} for each $j$
such that $i < j < \tcode{sizeof...(args)}$.
\item
Let \tcode{fargs} be a pack of the expressions
\tcode{args...[$j$]} for each $j$
such that $i < j < \tcode{sizeof...(args)}$.
\end{itemize}

\pnum
\mandates
The following are all \tcode{true}:
\begin{itemize}
\item \tcode{is_constructible_v<decay_t<F>, F>},
\item \tcode{(is_constructible_v<decay_t<Args>, Args> \&\& ...)}, and
\item \tcode{is_invocable_v<decay_t<F>, decay_t<Args>...> ||} \\ \tcode{is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>}.
\item \tcode{(is_constructible_v<decay_t<FArgs>, FArgs> \&\& ...)},
\item \tcode{is_invocable_v<decay_t<F>, decay_t<FArgs>...> ||} \\ \tcode{is_invocable_v<decay_t<F>, stop_token, decay_t<FArgs>...>}, and
\item No type is present more than once in the pack \tcode{remove_cvref_t<Attrs>}.
\end{itemize}

\pnum
Expand All @@ -2029,12 +2199,12 @@
The new thread of execution executes
\begin{codeblock}
invoke(auto(std::forward<F>(f)), get_stop_token(), // for \tcode{invoke}, see \ref{func.invoke}
auto(std::forward<Args>(args))...)
auto(std::forward<FArgs>(fargs))...)
\end{codeblock}
if that expression is well-formed,
otherwise
\begin{codeblock}
invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)
invoke(auto(std::forward<F>(f)), auto(std::forward<FArgs>(fargs))...)
\end{codeblock}
with the values produced by \tcode{auto}
being materialized\iref{conv.rval} in the constructing thread.
Expand All @@ -2045,6 +2215,11 @@
\end{note}
If the \tcode{invoke} expression exits via an exception,
\tcode{terminate} is called.
The parameters \tcode{attrs...}
%FIXME: why do we have iref{thread.attributes} for thread for the same wording,
%but not for jthread?
%While we're at it, could this not be a note?
can affect the behavior of the new thread.

\pnum
\sync
Expand Down
Loading