mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-17 12:44:42 +03:00
changed tabs into 4 spaces
This commit is contained in:
committed by
Thibault Kruse
parent
e8dea3807a
commit
757737e86d
@@ -10786,13 +10786,13 @@ A `thread` that has not been `detach()`ed when it is destroyed terminates the pr
|
|||||||
void f() { std::cout << "Hello "; }
|
void f() { std::cout << "Hello "; }
|
||||||
|
|
||||||
struct F {
|
struct F {
|
||||||
void operator()() { std::cout << "parallel world "; }
|
void operator()() { std::cout << "parallel world "; }
|
||||||
};
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::thread t1{f}; // f() executes in separate thread
|
std::thread t1{f}; // f() executes in separate thread
|
||||||
std::thread t2{F()}; // F()() executes in separate thread
|
std::thread t2{F()}; // F()() executes in separate thread
|
||||||
} // spot the bugs
|
} // spot the bugs
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
@@ -10800,13 +10800,13 @@ A `thread` that has not been `detach()`ed when it is destroyed terminates the pr
|
|||||||
void f() { std::cout << "Hello "; }
|
void f() { std::cout << "Hello "; }
|
||||||
|
|
||||||
struct F {
|
struct F {
|
||||||
void operator()() { std::cout << "parallel world "; }
|
void operator()() { std::cout << "parallel world "; }
|
||||||
};
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::thread t1{f}; // f() executes in separate thread
|
std::thread t1{f}; // f() executes in separate thread
|
||||||
std::thread t2{F()}; // F()() executes in separate thread
|
std::thread t2{F()}; // F()() executes in separate thread
|
||||||
|
|
||||||
t1.join();
|
t1.join();
|
||||||
t2.join();
|
t2.join();
|
||||||
@@ -10992,20 +10992,20 @@ A `wait` without a condition can miss a wakeup or wake up simply to find that th
|
|||||||
|
|
||||||
void thread1()
|
void thread1()
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
// do some work ...
|
// do some work ...
|
||||||
std::unique_lock<std::mutex> lock(mx);
|
std::unique_lock<std::mutex> lock(mx);
|
||||||
cv.notify_one(); // wake other thread
|
cv.notify_one(); // wake other thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread2()
|
void thread2()
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
std::unique_lock<std::mutex> lock(mx);
|
std::unique_lock<std::mutex> lock(mx);
|
||||||
cv.wait(lock); // might block forever
|
cv.wait(lock); // might block forever
|
||||||
// do work ...
|
// do work ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Here, if some other `thread` consumes `thread1`'s notification, `thread2` can wait forever.
|
Here, if some other `thread` consumes `thread1`'s notification, `thread2` can wait forever.
|
||||||
@@ -11015,30 +11015,30 @@ Here, if some other `thread` consumes `thread1`'s notification, `thread2` can wa
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class Sync_queue {
|
class Sync_queue {
|
||||||
public:
|
public:
|
||||||
void put(const T& val);
|
void put(const T& val);
|
||||||
void put(T&& val);
|
void put(T&& val);
|
||||||
void get(T& val);
|
void get(T& val);
|
||||||
private:
|
private:
|
||||||
mutex mtx;
|
mutex mtx;
|
||||||
condition_variable cond; // this controls access
|
condition_variable cond; // this controls access
|
||||||
list<T> q;
|
list<T> q;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Sync_queue<T>::put(const T& val)
|
void Sync_queue<T>::put(const T& val)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lck(mtx);
|
lock_guard<mutex> lck(mtx);
|
||||||
q.push_back(val);
|
q.push_back(val);
|
||||||
cond.notify_one();
|
cond.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Sync_queue<T>::get(T& val)
|
void Sync_queue<T>::get(T& val)
|
||||||
{
|
{
|
||||||
unique_lock<mutex> lck(mtx);
|
unique_lock<mutex> lck(mtx);
|
||||||
cond.wait(lck,[this]{ return !q.empty(); }); // prevent spurious wakeup
|
cond.wait(lck,[this]{ return !q.empty(); }); // prevent spurious wakeup
|
||||||
val=q.front();
|
val=q.front();
|
||||||
q.pop_front();
|
q.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
Now if the queue is empty when a thread executing `get()` wakes up (e.g., because another thread has gotton to `get()` before it),
|
Now if the queue is empty when a thread executing `get()` wakes up (e.g., because another thread has gotton to `get()` before it),
|
||||||
@@ -11251,15 +11251,15 @@ It's error-prone and requires expert level knowledge of language features, machi
|
|||||||
|
|
||||||
##### Example, bad
|
##### Example, bad
|
||||||
|
|
||||||
extern atomic<Link*> head; // the shared head of a linked list
|
extern atomic<Link*> head; // the shared head of a linked list
|
||||||
|
|
||||||
Link* nh = new Link(data,nullptr); // make a link ready for insertion
|
Link* nh = new Link(data,nullptr); // make a link ready for insertion
|
||||||
Link* h = head.load(); // read the shared head of the list
|
Link* h = head.load(); // read the shared head of the list
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (h->data<=data) break; // if so, insert elsewhere
|
if (h->data<=data) break; // if so, insert elsewhere
|
||||||
nh->next = h; // next element is the previous head
|
nh->next = h; // next element is the previous head
|
||||||
} while (!head.compare_exchange_weak(h,nh)); // write nh to head or to h
|
} while (!head.compare_exchange_weak(h,nh)); // write nh to head or to h
|
||||||
|
|
||||||
Spot the bug.
|
Spot the bug.
|
||||||
It would be really hard to find through testing.
|
It would be really hard to find through testing.
|
||||||
|
|||||||
Reference in New Issue
Block a user