| 26 | using boost::asio::yield_context; |
| 27 | |
| 28 | int main(int argc, char* argv[]) |
| 29 | { |
| 30 | try |
| 31 | { |
| 32 | if (argc < 2) |
| 33 | { |
| 34 | std::cerr << "Usage: parallel_grep <string> <files...>\n"; |
| 35 | return 1; |
| 36 | } |
| 37 | |
| 38 | // We use a fixed size pool of threads for reading the input files. The |
| 39 | // number of threads is automatically determined based on the number of |
| 40 | // CPUs available in the system. |
| 41 | thread_pool pool; |
| 42 | |
| 43 | // To prevent the output from being garbled, we use a strand to synchronise |
| 44 | // printing. |
| 45 | strand<thread_pool::executor_type> output_strand(pool.get_executor()); |
| 46 | |
| 47 | // Spawn a new coroutine for each file specified on the command line. |
| 48 | std::string search_string = argv[1]; |
| 49 | for (int argn = 2; argn < argc; ++argn) |
| 50 | { |
| 51 | std::string input_file = argv[argn]; |
| 52 | spawn(pool, |
| 53 | [=](yield_context yield) |
| 54 | { |
| 55 | std::ifstream is(input_file.c_str()); |
| 56 | std::string line; |
| 57 | std::size_t line_num = 0; |
| 58 | while (std::getline(is, line)) |
| 59 | { |
| 60 | // If we find a match, send a message to the output. |
| 61 | if (line.find(search_string) != std::string::npos) |
| 62 | { |
| 63 | dispatch(output_strand, |
| 64 | [=] |
| 65 | { |
| 66 | std::cout << input_file << ':' << line << std::endl; |
| 67 | }); |
| 68 | } |
| 69 | |
| 70 | // Every so often we yield control to another coroutine. |
| 71 | if (++line_num % 10 == 0) |
| 72 | post(yield); |
| 73 | } |
| 74 | }, detached); |
| 75 | } |
| 76 | |
| 77 | // Join the thread pool to wait for all the spawned tasks to complete. |
| 78 | pool.join(); |
| 79 | } |
| 80 | catch (std::exception& e) |
| 81 | { |
| 82 | std::cerr << "Exception: " << e.what() << "\n"; |
| 83 | } |
| 84 | |
| 85 | return 0; |