#ifndef common_h #define common_h #include "rng.h" #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; std::tuple parser(int argc, char *argv[]) { size_t ops = 1'000; size_t threads = std::thread::hardware_concurrency(); bool verbose = false; int option = 0; while ((option = getopt(argc, argv, "ho:t:v")) != -1) { switch (option) { case 'o': ops = atoi(optarg); break; case 't': threads = atoi(optarg); break; case 'v': verbose = true; break; default: std::cout << argv[0] << " options:\n" << "\t-h: help\n" << "\t-o: operations per thread, default: " << ops << "\n\t-t: number of threads, default: " << threads << "\n\t-v: verbose\n"; exit(EXIT_SUCCESS); break; } } return {ops, threads, verbose}; } template void worker(Stack &stack, size_t ops, bool verbose) { std::thread::id id = std::this_thread::get_id(); std::string pushing = std::format("{}: push\n", id); std::string popping = std::format("{}: pop\n", id); xorshift32 engine(std::hash{}(id)); while (ops--) { if (engine() & 1) // 50% push, 50% pop { stack.push(0xdeadbeef); if (verbose) std::cout << pushing; } else { auto val = stack.pop(); assert(!val || *val == 0xdeadbeef); if (verbose) std::cout << popping; } } } template void common_main(int argc, char *argv[]) { const auto [ops, threads, verbose] = parser(argc, argv); Stack stack; std::vector workers(threads); for (auto &w : workers) w = std::thread(worker, std::ref(stack), ops, verbose); for (auto &w : workers) w.join(); std::cout << ops * threads << '\n'; } #endif // common_h