// CPP program to demonstrate multithreading
// using three different callables.
#include <iostream>
#include <thread>
using namespace std;
// A dummy function
void foo(int Z)
{
for (int i = 0; i < Z; i++) {
cout << "Thread using function"
" pointer as callable\n";
}
}
// A callable object
class thread_obj {
public:
void operator()(int x)
{
for (int i = 0; i < x; i++)
cout << "Thread using function"
" object as callable\n";
}
};
int main()
{
cout << "Threads 1 and 2 and 3 "
"operating independently" << endl;
// This thread is launched by using
// function pointer as callable
thread th1(foo, 3);
// This thread is launched by using
// function object as callable
thread th2(thread_obj(), 3);
// Define a Lambda Expression
auto f = [](int x) {
for (int i = 0; i < x; i++)
cout << "Thread using lambda"
" expression as callable\n";
};
// This thread is launched by using
// lamda expression as callable
thread th3(f, 3);
// Wait for the threads to finish
// Wait for thread t1 to finish
th1.join();
// Wait for thread t2 to finish
th2.join();
// Wait for thread t3 to finish
th3.join();
return 0;
}
运行结果:
Threads 1 and 2 and 3 operating independently
Thread using function pointer as callable
Thread using lambda expression as callable
Thread using function pointer as callable
Thread using function pointer as callable
Thread using lambda expression as callable
Thread using lambda expression as callable
Thread using function object as callable
Thread using function object as callable
Thread using function object as callable
#include <vector>
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<int> cnt = {0};
void f()
{
for (int n = 0; n < 100000; ++n) {
cnt.fetch_add(1, std::memory_order_relaxed);
}
}
int main()
{
std::vector<std::thread> v;
for (int n = 0; n < 10; ++n) {
v.emplace_back(f);
}
for (auto& t : v) {
t.join();
}
std::cout << "Final counter value is " << cnt << '\n';
}
运行结果:
Final counter value is 1000000
释放获得顺序
若线程 A 中的一个原子存储带标签 memory_order_release ,而线程 B 中来自同一变量的原子加载带标签 memory_order_acquire ,则从线程 A 的视角先发生于原子存储的所有内存写入(非原子及宽松原子的),在线程 B 中成为可见副效应,即一旦原子加载完成,则保证线程 B 能观察到线程 A 写入内存的所有内容。
同步仅建立在释放和获得同一原子对象的线程之间。其他线程可能看到与被同步线程的一者或两者相异的内存访问顺序。
在强顺序系统( x86 、 SPARC TSO 、 IBM 主框架)上,释放获得顺序对于多数操作是自动进行的。无需为此同步模式添加额外的 CPU 指令,只有某些编译器优化受影响(例如,编译器被禁止将非原子存储移到原子存储-释放后,或将非原子加载移到原子加载-获得前)。在弱顺序系统( ARM 、 Itanium 、 Power PC )上,必须使用特别的 CPU 加载或内存栅栏指令。
互斥锁(例如 std::mutex 或原子自旋锁)是释放获得同步的例子:线程 A 释放锁而线程 B 获得它时,发生于线程 A 环境的临界区(释放之前)中的所有事件,必须对于执行同一临界区的线程 B (获得之后)可见。
compare_exchange_weak例子,
// atomic::compare_exchange_weak example:
#include <iostream> // std::cout
#include <atomic> // std::atomic
#include <thread> // std::thread
#include <vector> // std::vector
// a simple global linked list:
struct Node {
int value;
Node* next;
};
std::atomic<Node*> list_head (nullptr);
// append an element to the list
void append (int val) {
Node* oldHead = list_head;
Node* newNode = new Node {val,oldHead};
// what follows is equivalent to: list_head = newNode, but in a thread-safe way:
// 当list_head与期望值不相等时,更新oldHead为当前list_head值,并且返回false,更新新节点下一个结点为oldHead,循环进行
while (!list_head.compare_exchange_weak(oldHead,newNode))
newNode->next = oldHead;
}
void foo()
{
std::cout <<"run example foo"<< std::endl;
std::atomic<int> x(20);
int expect = 20;
std::cout << "previous expected value:" << expect << std::endl;
bool ret = x.compare_exchange_weak(expect,6);
//当前值与期望值expect相等,修改当前值为设定值6,返回true
std::cout << "operation successful:"<< (ret ? "yes":"no") << std::endl;
std::cout << "current expect:" << expect << std::endl;
std::cout << "current x:" << x.load() << std::endl;
}
void bar()
{
std::cout <<"run example bar"<< std::endl;
std::atomic<int> x(20);
int expect = 10;
std::cout << "previous expected value:" << expect << std::endl;
bool ret = x.compare_exchange_weak(expect,6);
//当前值与期望值expect不相等,修改期望值expect为设定值6,返回false
std::cout << "operation successful:"<< (ret ? "yes":"no") << std::endl;
std::cout << "current expect:" << expect << std::endl;
std::cout << "current x:" << x.load() << std::endl;
}
int main ()
{
foo();
bar();
// spawn 10 threads to fill the linked list:
std::vector<std::thread> threads;
for (int i=0; i<10; ++i) threads.push_back(std::thread(append,i));
for (auto& th : threads) th.join();
// print contents:
for (Node* it = list_head; it!=nullptr; it=it->next)
std::cout << ' ' << it->value;
std::cout << '\n';
// cleanup:
Node* it; while (it=list_head) {list_head=it->next; delete it;}
return 0;
}
运行结果:
run example foo
previous expected value:20
operation successful:yes
current expect:20
current x:6
run example bar
previous expected value:10
operation successful:no
current expect:20
current x:20
9 8 7 6 5 4 3 2 1 0
上面的代码实现了一个lock free无锁链表。
// using atomic_flag as a lock
#include <iostream> // std::cout
#include <atomic> // std::atomic_flag
#include <thread> // std::thread
#include <vector> // std::vector
#include <sstream> // std::stringstream
std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
std::stringstream stream;
void append_number(int x) {
while (lock_stream.test_and_set()) {}
stream << "thread #" << x << '\n';
lock_stream.clear();
}
int main ()
{
std::vector<std::thread> threads;
for (int i=1; i<=10; ++i) threads.push_back(std::thread(append_number,i));
for (auto& th : threads) th.join();
std::cout << stream.str();
return 0;
}
运行可能的结果:
thread #2
thread #1
thread #3
thread #4
thread #5
thread #6
thread #7
thread #8
thread #9
thread #10
我们如果修改函数append_number:
void append_number(int x) {
//while (lock_stream.test_and_set()) {}
stream << "thread #" << x << '\n';
//lock_stream.clear();
}
运行报错:
leetcode(86302,0x700005aec000) malloc: Double free of object 0x7fe30dd04080
leetcode(86302,0x700005aec000) malloc: *** set a breakpoint in malloc_error_break to debug
// using atomic_flag as a lock
#include <iostream> // std::cout
#include <atomic> // std::atomic_flag
void example()
{
std::atomic_flag flag = ATOMIC_FLAG_INIT;
//set flag value,return previous value
std::cout << "1.previous flag value:" << flag.test_and_set() << std::endl;
std::cout << "2.previous flag value:" << flag.test_and_set() << std::endl;
//clear the flag value
flag.clear();
std::cout << "3.previous flag value:"<<flag.test_and_set() << std::endl;
}
int main ()
{
example();
return 0;
}
运行结果:
1.previous flag value:0
2.previous flag value:1
3.previous flag value:0
程序代码:
#include <thread>
#include <atomic>
#include <cassert>
#include <vector>
#include <iostream>
std::vector<int> data;
std::atomic<int> flag = {0};
void thread_1()
{
data.push_back(42);
flag.store(1, std::memory_order_release);
}
/*
* Compares the contents of the contained value with expected:
- if true, it replaces the contained value with val (like store).
- if false, it replaces expected with the contained value .
* */
void thread_2()
{
int expected=1;
while (!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {
std::cout << expected << std::endl;
expected = 1;
}
}
void thread_3()
{
while (flag.load(std::memory_order_acquire) < 2)
;
assert(data.at(0) == 42); // 决不出错
}
int main()
{
std::thread a(thread_1);
std::thread b(thread_2);
std::thread c(thread_3);
a.join(); b.join(); c.join();
return 0;
}
可能的输出:
空或者0
原因是依赖线程1和线程2执行的先后顺序,如果先执行线程1,将flag的值设置为1后,线程2中条件不满足就不再打印0了。