74 lines
3.0 KiB
C++
74 lines
3.0 KiB
C++
#include <cstdio>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include <atomic>
|
|
#include <mutex>
|
|
#include <stdexcept>
|
|
#include "solution.cpp"
|
|
|
|
static int failures = 0;
|
|
#define CHECK(cond, name) do { if (cond) std::printf("ok %s\n", name); \
|
|
else { std::printf("FAIL %s (line %d)\n", name, __LINE__); ++failures; } } while (0)
|
|
|
|
int main() {
|
|
// Базовая дисциплина
|
|
{
|
|
BlockingQueue q(2);
|
|
q.push(1);
|
|
q.push(2);
|
|
CHECK(q.size() == 2, "size() == 2 после двух push");
|
|
int v = 0;
|
|
CHECK(q.pop(v) && v == 1, "pop -> 1 (FIFO)");
|
|
CHECK(q.pop(v) && v == 2, "pop -> 2 (FIFO)");
|
|
q.close();
|
|
CHECK(!q.pop(v), "после close и опустошения pop -> false");
|
|
bool threw = false;
|
|
try { q.push(3); } catch (const std::runtime_error&) { threw = true; }
|
|
CHECK(threw, "push после close -> std::runtime_error");
|
|
}
|
|
// Продюсеры/потребители под нагрузкой
|
|
{
|
|
const int P = 4, C = 4, PER = 20000, C3 = 64;
|
|
BlockingQueue q(C3);
|
|
std::atomic<int> pushed{0};
|
|
std::atomic<long long> sum{0};
|
|
std::atomic<int> popped{0};
|
|
std::atomic<int> over{0};
|
|
|
|
auto producer = [&](int pid) {
|
|
for (int i = 0; i < PER; ++i) {
|
|
q.push(pid * 1000000 + i);
|
|
pushed.fetch_add(1, std::memory_order_relaxed);
|
|
if (q.size() > C3) over.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
};
|
|
auto consumer = [&](int) {
|
|
int v = 0;
|
|
while (q.pop(v)) {
|
|
sum.fetch_add(v, std::memory_order_relaxed);
|
|
popped.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
};
|
|
|
|
std::vector<std::thread> ts;
|
|
for (int i = 0; i < C; ++i) ts.emplace_back(consumer, i);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
for (int i = 0; i < P; ++i) ts.emplace_back(producer, i);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
while (pushed.load() < P * PER) std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
q.close();
|
|
for (auto& t : ts) t.join();
|
|
|
|
long long expect = 0;
|
|
for (int p = 0; p < P; ++p) for (int i = 0; i < PER; ++i) expect += (long long)p * 1000000 + i;
|
|
std::printf(" (вставлено=%d, извлечено=%d, переполнений=%d)\n",
|
|
pushed.load(), popped.load(), over.load());
|
|
CHECK(pushed.load() == P * PER, "все вставки выполнены (нет потерь)");
|
|
CHECK(popped.load() == P * PER, "извлечено ровно столько же (нет дублей/потерь)");
|
|
CHECK(sum.load() == expect, "сумма значений совпадает с эталоном");
|
|
CHECK(over.load() == 0, "size() не превышал capacity");
|
|
}
|
|
std::printf(failures ? "\nFAILURES: %d\n" : "\nALL PASS\n", failures);
|
|
return failures ? 1 : 0;
|
|
}
|