-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdetectPrimes.cpp
283 lines (221 loc) · 7.92 KB
/
detectPrimes.cpp
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// =============================================================================
// You must modify this file and then submit it for grading to D2L.
// =============================================================================
#include "detectPrimes.h"
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <atomic>
#include <math.h>
#include <pthread.h>
//This makes our life easier
using namespace std;
//-------------------------------- GLOBAL VARIABLES -----------------------------//
//Initialized global variables
atomic<bool> flag (false);
atomic<bool> global_finished (false);
atomic<bool> task1 (false);
//Thread-synchronization variables.
pthread_barrier_t myBarrier;
pthread_mutex_t myMutex;
double count1;
//Globalized variables from trivial cases.
int64_t i = 5;
int64_t nextNum;
//Global variables.
int global_threads;
vector<int64_t> global_nums;
bool global_Prime;
bool value;
vector<bool> value_vector;
vector<int64_t> result;
//--------------------------------- TRIVIAL CASES -------------------------------//
// returns true if n is prime, otherwise returns false
// param:
// n: number needed to check.
// start: start index for while loop.
// work: how many times i need to be increased.
static bool is_prime(int64_t n, int64_t i, int64_t max)
{
//Parallelize the inner loop.
// handle trivial cases
if (n < 2) return false;
if (n <= 3) return true; // 2 and 3 are primes
if (n % 2 == 0) return false; // handle multiples of 2
if (n % 3 == 0) return false; // handle multiples of 3
// try to divide n by every number 5 .. sqrt(n)
//int64_t i = 5;
//int64_t max = sqrt(n)
//Handle thread cancellation
flag.store(false, memory_order_relaxed);
while (i <= max && flag == false) {
if ((n % i == 0) || (n % (i + 2) == 0)) {
flag.store(true, memory_order_relaxed);
return false;
}
i += 6;
}
// didn't find any divisors, so it must be a prime
return true;
}
//-------------------------------- DECLARE FUNCTIONS ---------------------------//
static void serial_algorithm(int res, int tid_int);
static void parallel_algorithm(int tid_int);
static void serial_algorithm2(int res, int tid_int);
//-------------------------------- THREAD FUNCTIONS ---------------------------//
void * thread_f1(void * tid){
int tid_int;
tid_int = (long int) tid;
//Repeat forever:
while(1){
// wait for all threads to be synchronized
int res = pthread_barrier_wait(&myBarrier);
//------------------- SERIAL TASK --------------------------------//
//Algorithm for serial task.
serial_algorithm(res, tid_int);
// wait for all threads to be synchronized
pthread_barrier_wait(&myBarrier);
//------------------- PARALLEL TASK ------------------------------//
//executed by all threads, via barrier
// if global_finished flag is set, exit thread.
if (global_finished == true) {
//cout << finished << endl;
break;
}
//Algorithm for parallel task.
parallel_algorithm(tid_int);
// wait for all threads to be synchronized
pthread_barrier_wait(&myBarrier);
//------------------ SERIAL TASK 2 -------------------------//
//Algorithm for serial task.
serial_algorithm2(res, tid_int);
}
//Exit thread
pthread_exit(NULL);
}
//----------------- SERIAL TASK ALGORITHM --------------------------//
static void serial_algorithm(int res, int tid_int) {
//This part of the code was taken from barrierExp2.cpp provided by tutorials.
//serial task - pick one thread using barrier
if( res == PTHREAD_BARRIER_SERIAL_THREAD)
{
//if no more numbers left then set global_finished = true
if (count1 != global_nums.size()){
// pick a number
nextNum = global_nums[count1];
// update flag!
task1.store(false, std::memory_order_relaxed);
if (nextNum < 1000000){
// update flag!
task1.store(true, std::memory_order_relaxed);
value = is_prime(nextNum, 5, (int) sqrt(nextNum));
value_vector[tid_int] = value;
}
count1++;
}
//otherwise: divide work for each thread.
else {
global_finished.store(true,std::memory_order_relaxed); //It indicate to all threads to quit.
}
}
}
//----------------- PARALLEL TASK ALGORITHM --------------------------//
static void parallel_algorithm(int tid_int) {
//serial task – pick one thread using barrier
//combine the per-thread results and update the result[] array if necessary
int64_t max = sqrt(nextNum);
bool value;
if (task1 == false){
//divide work among threads
int64_t split;
split = max / (6 * global_threads);
int64_t start_x;
start_x = (i + split * 6 * tid_int);
int64_t end_x;
end_x = (start_x + split*6);
//In this case we would have 5 mod 6.
//checks if the value of 5 is greater than the square root.
if (i >= max){
end_x = max; //Sets end_x to be square root.
}
int nThreads = global_threads - 1;
//checks whether tid_int is equivalent to nThread parameter.
if (tid_int == nThreads) {
while(end_x < max){
end_x += 6; //Increment end_x by 6 if condition satisfied.
}
if (end_x > max) {
end_x -= 6; // Increment end_X by 6 if condition satisfied.
}
}
//Set our boolean variable to the function is_prime.
value = is_prime(nextNum, start_x, end_x);
//We want to prevent multiple threads from assessing the same memory.
//Thread locks code.
pthread_mutex_lock(&myMutex);
value_vector[tid_int] = value;
//Thread unlocks code.
pthread_mutex_unlock(&myMutex);
}
}
//----------------- SERIAL TASK 2 ALGORITHM --------------------------//
static void serial_algorithm2(int res, int tid_int) {
// combine per thread result
global_Prime = true;
if ( res == PTHREAD_BARRIER_SERIAL_THREAD){
//Check cases for task1
switch (task1){
case true:
//Concatenate properties
global_Prime &= value_vector[tid_int];
break;
case false:
for (int i = 0; i < global_threads; i++){
//Concatenate properties
global_Prime &= value_vector[i];
if (value_vector[i] == 0) {
break;
}
}
}
if (global_Prime) {
result.push_back(nextNum);
}
}
}
//------------------------------- DETECT PRIMES ------------------------------------//
// This function takes a list of numbers in nums[] and returns only numbers that
// are primes.
//
// The parameter n_threads indicates how many threads should be created to speed
// up the computation.
// -----------------------------------------------------------------------------
// You will most likely need to re-implement this function entirely.
// Note that the current implementation ignores n_threads. Your multithreaded
// implementation must use this parameter.
std::vector<int64_t>
detect_primes(const std::vector<int64_t> & nums, int n_threads)
{
// initialize variables
global_nums = nums;
value_vector.resize(n_threads);
//-------------------------------- BARRIERS ----------------------//
//Parse command line arguments
// create a barrier for total number of threads.
global_threads = n_threads;
pthread_barrier_init(&myBarrier, NULL, n_threads);
//-------------------------------- USE ALL THREAD ----------------------//
//Declare thread
pthread_t t1[n_threads];
//Create actual thread
for (long i = 0; i < n_threads; i++){
pthread_create(&t1[i], NULL, thread_f1, (void*) i);
}
//Wait for join Thread
for (int i = 0; i < n_threads; i++){
pthread_join(t1[i], NULL);
}
return result;
}