Skip to content

Commit 7ef6861

Browse files
committed
Rewording in threads.
1 parent adb6fbc commit 7ef6861

File tree

1 file changed

+70
-66
lines changed

1 file changed

+70
-66
lines changed

threads.tex

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -938,37 +938,38 @@
938938
\label{CONDITION_VARIABLES}
939939

940940
\begin{itemize}
941-
\item in other words -- conditional variables are handy in situation when a
942-
thread needs to test the state of \emsl{shared} data (e.g. number of queues
943-
in queue), and voluntarily put itself to sleep, when desired state has not
944-
been reached. The sleeping thread is then woken up by another thread that
945-
changed the state of the data, so the situation which the first thread was
946-
waiting on actually happened (e.g. by inserting a item into queue).
947-
The second thread wakes the first one by calling a designated function.
948-
If no thread is sleeping at the moment, the function will have no effect --
949-
nothing will be saved anywhere, like it never happened.
950-
\item A condition variable, which is opaque type for the programmer, is not
941+
\item In other words -- conditional variables are handy in a situation when a
942+
thread needs to test the state of \emsl{shared} data (e.g. number of elements in
943+
a queue) and voluntarily put itself to sleep if the state is not as desired.
944+
The sleeping thread may be woken up by another thread after the latter
945+
changed the state of the data in a way that the situation which the first thread
946+
was waiting on actually happened (e.g. by inserting an item into a queue). The
947+
second thread wakes the first one by calling a designated function. If no
948+
thread is sleeping at the moment, that function would have no effect -- nothing
949+
will be saved anywhere, it is as if it never happened.
950+
\item A condition variable, which is an opaque type for the programmer, is not
951951
associated with a concrete condition like ``\emph{\texttt{n} is greater than
952-
7}''. Conditional variable can be in fact compared to a flag of certain color;
953-
if it is lifted up, it means that the threads waiting for the flag to be waved
954-
are informed (= woken up) and can use this information according its own
955-
judgment. Some threads can wait for \texttt{n} to be bigger than 7, the other
956-
can be waiting solely for \texttt{n} to change anyhow. It is only up to the
957-
programmer, if for concrete situation uses just one condition variable or
958-
for all situations. For the second situation, the threads waiting on
959-
\texttt{n == 7} have to always test \texttt{n}, because they know that they
960-
are woken up whenever the variable changed. If the variable is not equal to 7,
961-
it will voluntarily put itself to sleep. How it is explained further,
962-
the \emsl{test is necessary to do after wake up}, even if dedicated conditional
963-
variable is used -- it can happen that the system can wake up the sleeping
964-
thread (because of various implementation reasons) without being caused by
965-
another thread.
952+
7}''. A conditional variable may in fact be compared to a flag of a certain
953+
color; if it is lifted up, it means that the threads waiting for the flag to be
954+
raised are informed (= woken up) and may use this information to its own
955+
judgment. Some threads may wait for \texttt{n} to be bigger than 7, some other
956+
may be waiting solely for \texttt{n} to change, and another then for \texttt{n}
957+
to become 99. It is only up to the programmer whether a separate condition
958+
variable will be used for all states of \texttt{n} (i.e. we would use multiple
959+
flags of different colors) or whether a single condition variable will be used
960+
(the same flag color for all situations). For the latter, the threads waiting
961+
on \texttt{n > 7} and \texttt{n == 99} must always test \texttt{n} as they know
962+
that they are woken up whenever the variable changed. If the variable is not
963+
equal to 7 the thread must voluntarily put itself to sleep again. As it is
964+
explained further, the \emsl{test is necessary to perform after an every
965+
wake-up} even if a dedicated conditional variable is used for every possible
966+
state -- it may happen that the system can wake up a sleeping thread (because
967+
of various implementation reasons) without any other thread causing this; it is
968+
called a \emsl{spurious wakeup}.
966969
\end{itemize}
967970

968971
%%%%%
969972

970-
%%%%%
971-
972973
ifdef([[[NOSPELLCHECK]]], [[[
973974
\pdfbookmark[1]{pthread\_cond\_init, pthread\_cond\_destroy,%
974975
pthread\_cond\_wait}{pthreadcondvarfncs}
@@ -1005,6 +1006,9 @@
10051006
\end{slide}
10061007

10071008
\begin{itemize}
1009+
\item While the condition variables are used for putting threads to sleep and
1010+
waking them up, given that we work with shared data, there is always a mutex
1011+
involved when working with a condition variable.
10081012
\item It is necessary to test the condition after the thread locks the mutex
10091013
and before the \texttt{pthread\_cond\_wait} is called. If the thread does not
10101014
perform this operation, it could be put to sleep indefinitely because the
@@ -1017,12 +1021,11 @@
10171021
\item The conditional variables API works thanks to the fact that when entering
10181022
critical section the mutex is locked by the thread and the
10191023
\emsl{\texttt{pthread\_cond\_wait} function will unlock the mutex before putting
1020-
the thread to sleep}. Before exiting from the function the mutex is again
1021-
locked.
1022-
It can therefore happen that the thread is woken up while waiting on a
1023-
conditional variable and then sleeps again when waiting for the mutex.
1024-
There is nothing complicated about this, it is merely mutual exclusion of
1025-
threads in critical section.
1024+
the thread to sleep}. Before exiting from the function the mutex is locked
1025+
again. It may therefore happen that the thread is woken up while waiting on a
1026+
conditional variable and then put to sleep again when hitting a mutex already
1027+
locked by another thread. There is nothing complicated about this, it is merely
1028+
a mutual exclusion of threads in a critical section.
10261029
\end{itemize}
10271030

10281031
%%%%%
@@ -1061,31 +1064,31 @@
10611064
\end{slide}
10621065

10631066
\begin{itemize}
1064-
\item one conditional variable can be used to announce multiple situations
1065-
at once -- e.g. when inserting or removing an item to/from a queue.
1066-
Because of this, it is necessary to test the condition the thread is waiting
1067-
for. Another consequence of this is that it is necessary to use broadcast
1068-
in such situation. Let's assume that both readers and writers are waiting for
1069-
condition ``state of queue has changed''. If only single wake-up event is made
1070-
after item insertion to the queue, then another writer can be woken up,
1071-
which is however waiting for different event -- item removal. Thus, the message
1072-
will remain in the queue until a reader is woken up.
1073-
\item A thread can be woken up by another thread also in case when a condition
1074-
variable is associated with concrete event, which is no longer true after
1075-
the waiting thread is woken up.
1076-
Let's consider this situation: a thread signals a condition change and right
1077-
after that another thread locks the mutex and performs an action which
1078-
invalidates the condition, e.g. removing a item from a queue when the event was
1079-
``there is a messages in the queue''. Thus the thread which is woken up
1080-
finds the queue empty. This is another reason why the condition variable
1081-
\emsl{always} has to be tested in a cycle.
1067+
\item One conditional variable can be used to announce multiple situations at
1068+
once -- e.g. when inserting or removing an item to/from a queue. Because of
1069+
this, it is necessary to test the condition the thread is waiting for. Another
1070+
consequence of this is that it is necessary to use a broadcast in such a
1071+
situation. Let us assume that both readers and writers are waiting for a
1072+
condition ``state of the queue has changed''. If only a single wake-up event is
1073+
made after an item insertion to the queue, a writer may be woken up but it is
1074+
however waiting for a different event -- an item removal, so it puts itself to
1075+
sleep again. Thus, the message will remain in the queue until a reader is woken
1076+
up.
1077+
\item A thread may be woken up by another thread even in a case when a condition
1078+
variable is associated with a specific event that is no longer true after the
1079+
waiting thread is woken up. Let's consider this situation: a thread signals a
1080+
condition change and right after that another thread locks the mutex and
1081+
performs an action which invalidates the condition, e.g. removing an item from a
1082+
queue while the event was ``there is an item in the queue''. So, the thread
1083+
woken up finds the queue empty. That is another reason why the condition the
1084+
thread is waiting for must be \emsl{always} tested in a cycle.
10821085
\item It is also possible that a thread is woken up and the condition is not
1083-
true due to concrete implementation. That's another reason to use the cycle.
1086+
true due to a spurious wake-up already mentioned in a previous page. So again,
1087+
the loop must be used.
10841088
\item The \texttt{abstime} parameter of the \texttt{pthread\_cond\_timedwait}
1085-
function is absolute time, i.e. the timeout expires when system time reaches
1086-
the value greater or equal to \texttt{abstime}. The absolute time is used
1087-
so that it is not necessary to recompute the time difference after wake-up
1088-
events.
1089+
function is absolute time, i.e. the timeout expires when the system time reaches
1090+
the value greater or equal to \texttt{abstime}. The absolute time is used so
1091+
that it is not necessary to recompute the time difference after wake-up events.
10891092
\end{itemize}
10901093

10911094
%%%%%
@@ -1111,14 +1114,14 @@
11111114

11121115
\begin{itemize}
11131116
\prgchars
1114-
\item The first piece of code is waiting for the condition to change.
1115-
If this happens, the data changed and can therefore be processed.
1116-
The second piece of code (executed in different thread) prepares the
1117-
data so it can be processed. Once ready, it will signal the consumer.
1118-
\item The \texttt{pthread\_cond\_wait} function will automatically unlock mutex
1119-
and put the thread to sleep. Once the thread is woken up, it will lock the
1120-
mutex first (this will be done by the condition variables implementation)
1121-
and only after that \texttt{pthread\_cond\_wait} will return.
1117+
\item The first piece of code is waiting for the condition to change. If this
1118+
happens, the data changed and can therefore be processed. The second piece of
1119+
code (executed in a different thread) prepares the data so it can be processed.
1120+
Once ready, it will signal the consumer. \item The \texttt{pthread\_cond\_wait}
1121+
function will automatically unlock the mutex and put the thread to sleep. Once
1122+
the thread is woken up, the system will lock the mutex first (this will be done
1123+
by the condition variable implementation) and only after that
1124+
\texttt{pthread\_cond\_wait} will return.
11221125
\item When signalling that something has changed, it does not mean that after
11231126
the change the condition will be true. Moreover,
11241127
\texttt{pthread\_cond\_wait} can return even if no thread called
@@ -1127,9 +1130,10 @@
11271130
going to sleep again.
11281131
\item The mutex in the example above is unlocked only after the condition
11291132
was signalled however it is not necessary. The signalling can be done
1130-
after unlocking and in such case it can be more efficient (depending on
1131-
given implementation) because the thread that has been woken up will not
1132-
get blocked by the mutex which is held when signalling in critical section.
1133+
after unlocking and in such a case it can be more efficient (depending on
1134+
a given implementation) because the thread that has been woken up will not get
1135+
immediatelly blocked by the mutex which is still held by the thread signalling
1136+
from within the critical section.
11331137
\item \label{QUEUESIMULATION} Example:
11341138
\example{cond-variables/queue-simulation.c}
11351139
\end{itemize}

0 commit comments

Comments
 (0)