#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
#include <algorithm>
#include <cassert>
class interlocked_queue
{
private:
std::queue<int> _queue;
public:
interlocked_queue(void) = default;
void push(int value)
{
_queue.push(value);
}
int pop(void)
{
int result = _queue.front();
_queue.pop();
return result;
}
bool empty(void)
{
return _queue.empty();
}
};
class atomic_bool
{
private:
bool _value;
public:
atomic_bool(void)
: _value(false)
{ }
operator bool (void)
{
return _value;
}
atomic_bool& operator = (bool value)
{
_value = value;
return *this;
}
};
struct shared_data
{
std::size_t count;
int range;
atomic_bool done_generating;
atomic_bool done_testing;
interlocked_queue generated;
interlocked_queue primes;
interlocked_queue non_primes;
};
void* generator_main(void* raw_ptr)
{
assert(raw_ptr);
shared_data& data = *static_cast<shared_data*>(raw_ptr);
for(std::size_t i=0; i!=data.count; ++i)
data.generated.push(1 + std::rand() % data.range);
data.done_generating = true;
return nullptr;
}
bool is_prime(const std::vector<int>& primes, int p)
{
if(p <= 1) return true;
return std::find_if(
primes.begin(),
primes.end(),
[p](int div) -> bool
{
return (p != div) && (p % div == 0);
}
) == primes.end();
}
void update_primes(std::vector<int>& primes, int n)
{
int p = primes.back()+1;
while(true)
{
if(is_prime(primes, p))
{
primes.push_back(p);
if(p >= n) break;
}
++p;
}
}
void* tester_main(void* raw_ptr)
{
assert(raw_ptr);
shared_data& data = *static_cast<shared_data*>(raw_ptr);
std::vector<int> primes = {2, 3, 5, 7};
while(!data.done_generating || !data.generated.empty())
{
int candidate = data.generated.pop();
if(primes.back() < candidate)
update_primes(primes, candidate);
if(is_prime(primes, candidate))
data.primes.push(candidate);
else data.non_primes.push(candidate);
}
data.done_testing = true;
return nullptr;
}
void* printer_main(void* raw_ptr)
{
assert(raw_ptr);
shared_data& data = *static_cast<shared_data*>(raw_ptr);
int p, n;
int count_p = 0, count_n = 0;
int min_p = data.range, max_p = 0;
int min_n = data.range, max_n = 0;
bool has_p = false, has_n = false;
while(
(!data.done_testing) ||
(has_p=!data.primes.empty()) ||
(has_n=!data.non_primes.empty())
)
{
if(has_p)
{
p = data.primes.pop();
if(min_p > p) min_p = p;
if(max_p < p) max_p = p;
++count_p;
}
if(has_n)
{
n = data.non_primes.pop();
if(min_n > n) min_n = n;
if(max_n < n) max_n = n;
++count_n;
}
}
std::cout << "Generated " << data.count << " numbers ";
std::cout << "in range <1, " << data.range << ">" << std::endl;
std::cout << "Primes: " << count_p;
std::cout << " (" << ((1000 * count_p)/data.count)*0.1 << "%)";
std::cout << ", min = " << min_p << ", max = " << max_p << std::endl;
std::cout << "Non-primes: " << count_n;
std::cout << " (" << ((1000 * count_n)/data.count)*0.1 << "%)";
std::cout << ", min = " << min_n << ", max = " << max_n << std::endl;
return nullptr;
}
int main(int argc, const char* argv[])
{
std::srand(::getpid());
shared_data data;
data.count = (argc>1)?std::atoi(argv[1]):0;
if(data.count <= 0) data.count = 1000;
data.range = (argc>2)?std::atoi(argv[2]):0;
if(data.range <= 0) data.range = 10000;
generator.wait_for();
tester.wait_for();
printer.wait_for();
return 0;
}