parallel_grep.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //
  2. // parallel_grep.cpp
  3. // ~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #include <boost/asio/dispatch.hpp>
  11. #include <boost/asio/post.hpp>
  12. #include <boost/asio/spawn.hpp>
  13. #include <boost/asio/strand.hpp>
  14. #include <boost/asio/thread_pool.hpp>
  15. #include <boost/thread/thread.hpp>
  16. #include <boost/bind.hpp>
  17. #include <fstream>
  18. #include <iostream>
  19. #include <string>
  20. using boost::asio::dispatch;
  21. using boost::asio::spawn;
  22. using boost::asio::strand;
  23. using boost::asio::thread_pool;
  24. using boost::asio::yield_context;
  25. void print_match(std::string input_file, std::string line)
  26. {
  27. std::cout << input_file << ':' << line << std::endl;
  28. }
  29. void search_file(std::string search_string, std::string input_file,
  30. strand<thread_pool::executor_type> output_strand, yield_context yield)
  31. {
  32. std::ifstream is(input_file.c_str());
  33. std::string line;
  34. std::size_t line_num = 0;
  35. while (std::getline(is, line))
  36. {
  37. // If we find a match, send a message to the output.
  38. if (line.find(search_string) != std::string::npos)
  39. {
  40. dispatch(output_strand, boost::bind(&print_match, input_file, line));
  41. }
  42. // Every so often we yield control to another coroutine.
  43. if (++line_num % 10 == 0)
  44. post(yield);
  45. }
  46. }
  47. int main(int argc, char* argv[])
  48. {
  49. try
  50. {
  51. if (argc < 2)
  52. {
  53. std::cerr << "Usage: parallel_grep <string> <files...>\n";
  54. return 1;
  55. }
  56. // We use a fixed size pool of threads for reading the input files. The
  57. // number of threads is automatically determined based on the number of
  58. // CPUs available in the system.
  59. thread_pool pool;
  60. // To prevent the output from being garbled, we use a strand to synchronise
  61. // printing.
  62. strand<thread_pool::executor_type> output_strand(pool.get_executor());
  63. // Spawn a new coroutine for each file specified on the command line.
  64. std::string search_string = argv[1];
  65. for (int argn = 2; argn < argc; ++argn)
  66. {
  67. std::string input_file = argv[argn];
  68. spawn(pool, boost::bind(&search_file,
  69. search_string, input_file, output_strand, _1));
  70. }
  71. // Join the thread pool to wait for all the spawned tasks to complete.
  72. pool.join();
  73. }
  74. catch (std::exception& e)
  75. {
  76. std::cerr << "Exception: " << e.what() << "\n";
  77. }
  78. return 0;
  79. }