-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatomicDemo_usingSumOfNumbers.cpp
More file actions
116 lines (90 loc) · 3.27 KB
/
atomicDemo_usingSumOfNumbers.cpp
File metadata and controls
116 lines (90 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <thread>
#include <vector>
#include <atomic> // Tool of lock-free programming
#include <mutex>
using namespace std;
mutex m1;
void Sumup(atomic<int>& Sum, vector<int>& myVector, int Start, int End) {
for (int i = Start; i <= End; ++i) {
//Sum = Sum+ myVector[i];// + is not atomic
Sum += myVector[i];//+= operator is now atomic
}
cout << Sum << endl;
}
void sumup(int& sum, vector<int>& myVector, int Start, int End) {
for (int i = Start; i <= End; ++i) {
//Sum = Sum+ myVector[i];
// Here value of sum before operation can be accessed by multiple threads
// sum is thread is not safe and therefore the value calculated may be incorrect
sum += myVector[i];
}
cout << sum << endl;
}
void sumup1(int& sum, vector<int>& myVector, int Start, int End) {
for (int i = Start; i <= End; ++i) {
//Sum = Sum+ myVector[i];
lock_guard<mutex> Lock(m1);
// locking the thread and taking control of m1 here makes sure that
// no two threads are accessing sum variable at a time
sum += myVector[i];
}
cout << sum << endl;
}
int main() {
int sum{ 0 };
vector<int> myVector;
for (int i = 0; i < 40000; ++i) {
myVector.emplace_back(rand() % 100);
}
for (int i = 0; i < 40000; ++i) {
sum += myVector[i];
}
cout << "sequential sum = " << sum << endl;
//Calculating sum with sumup function will not be the same as sum calculated sequentially
// This is because, ref(sum) is not protected by any lock and hence
//multiple threads can have same value before their operation
// This is the kind of scenario where atomic will be useful
// Atomic provides synchronization control without using locks
sum = 0;
thread T[4];
T[0] = thread(sumup, ref(sum), ref(myVector), 0, 9999);
T[1] = thread(sumup, ref(sum), ref(myVector), 10000, 19999);
T[2] = thread(sumup, ref(sum), ref(myVector), 20000, 29999);
T[3] = thread(sumup, ref(sum), ref(myVector), 30000, 39999);
for (int i = 0; i < 4; ++i) T[i].join();
cout << "sum = " << sum << endl;
cout << "*****************" << endl;
sum = 0;
// sumup1 function uses a traditional lock to over come error described above
T[0] = thread(sumup1, ref(sum), ref(myVector), 0, 9999);
T[1] = thread(sumup1, ref(sum), ref(myVector), 10000, 19999);
T[2] = thread(sumup1, ref(sum), ref(myVector), 20000, 29999);
T[3] = thread(sumup1, ref(sum), ref(myVector), 30000, 39999);
for (int i = 0; i < 4; ++i) T[i].join();
cout << "sum1 = " << sum << endl;
atomic<int> Sum{ 0 };//+= will also be atomic
T[0] = thread(Sumup, ref(Sum), ref(myVector), 0, 9999);
T[1] = thread(Sumup, ref(Sum), ref(myVector), 10000, 19999);
T[2] = thread(Sumup, ref(Sum), ref(myVector), 20000, 29999);
T[3] = thread(Sumup, ref(Sum), ref(myVector), 30000, 39999);
for (int i = 0; i < 4; ++i) T[i].join();
cout << "Sum = " << Sum << endl;
return 0;
}
/*
for increment
loads the value from memory to a register
increments the content of the register
saves the register back to memory.
*/
/*
what types can be made atomic??
--> All trivially copyable type can be made atomic (Primitive variables)
What operations can be done?
-> assigment, ++, +=, |=
*= is not supported on atomic variables
there are some special atomic operations as well, for eg: load, store, exchange
I'll add a code describing their applications
atomicity is hardware dependent.
*/