2

I wrote a program to search a file by name on system using std::filesystem (recursive search using std::filesystem::recursive_directory_iterator). It works properly if I use only one main thread, execution time ~1 second, if I start from root ("/") directory on Linux. The problem: when I try to run this program using more than one thread, I get Aborted (core dumped), and filesystem error: recursive directory iterator cannot open directory: Not a directory. I want to run the function

bool SearchFile::find_file_in_directory(const std::string file_name, fs::path path) 

in 8 threads concurrently but with different parameters (path parameter will be another). I tried to implement multithreading this way: Calculate number of ALL existing files on system, then divide this number by number of threads, and give each thread entry directory to start searching. Also I have my own class for working with files called SearchFile (sf). Code listed below:

Firstly method for one thread (it works as I need):

bool SearchFile::find_file_from_directory(const std::string file_name,
                                          fs::path path) {
  if (fs::is_directory(path))
    for (auto &p : fs::recursive_directory_iterator(
             path, fs::directory_options::skip_permission_denied)) {
      path = p;
      if (path.filename() == file_name) {
        curr_path = path;
        return true;
      } else {
        // uncomment this line to see how the function search file
        // std::cout<<path<<"\n";
        continue;
      }
    }
  else
    std::cout << "Entered path is not a directory\n";

  return false;

  std::cout << "File doesn`t exist\n";
  return false;
}

Methods from SearchFile i use:

bool SearchFile::find_file_in_directory(const std::string file_name,
                                        fs::path path) {
  if (fs::is_directory(path))
    path /= file_name;
  if (fs::exists(path)) {
    return true;
  } else
    std::cout << "Entered path is not a directory\n";
  return false;

  std::cout << "File doesn`t exist\n";
  return false;
}

u_int SearchFile::get_num_of_files_recursively(const fs::path path) {
  u_int num = 0;
  if (fs::is_directory(path)) {
    for (fs::recursive_directory_iterator it(
             path, fs::directory_options::skip_permission_denied);
         it != fs::recursive_directory_iterator(); ++it) {
      num++;
    }
  } else {
    std::cout << "Entered path is not a directory\n";
    return 0;
  }
  return num;
}

main.cpp

#include <iostream>
#include <string>
#include <thread>
//#include "library/searchfile.h"
#include <condition_variable>
#include <fstream>
#include <vector>
//#pragma once
#include <filesystem>

SearchFile sf;
std::condition_variable cv;
std::vector<fs::path> arr;

void do_division(const fs::path path, const u_int times) {
  u_int files_num = sf.get_num_of_files_recursively(path),
        part = files_num / times;
  u_int i = 0;
  arr.push_back(path);
  for (fs::recursive_directory_iterator it(path, fs::directory_options::skip_permission_denied);
       it != fs::recursive_directory_iterator(); ++it) {
    if (i == part) {
      arr.push_back(it->path());
      part += part;
    }
    i++;
  }
}

void do_job(const fs::path path, const std::string name) noexcept {
  for (auto &p : fs::recursive_directory_iterator(path, fs::directory_options::skip_permission_denied)) {
    std::cout << std::this_thread::get_id() << " - " << p.path() << "\n";

    if (sf.find_file_in_directory(name, p.path())) {
      cv.notify_all();
      std::fstream f;
      std::string path = p.path().string();
      f.open(path);
      f << path;
      f.close();
      return;
    }
  }
}

int main() {
  std::string filename = "MyFile.txt";
  std::string path = "/";

  do_division("/", 8);

  while (1) {
    std::thread t1(do_job, arr[0], filename);
    t1.detach();

    std::thread t2(do_job, arr[1], filename);
    t2.detach();

    std::thread t3(do_job, arr[2], filename);
    t3.detach();

    std::thread t4(do_job, arr[3], filename);
    t4.detach();

    std::thread t5(do_job, arr[4], filename);
    t5.detach();

    std::thread t6(do_job, arr[5], filename);
    t6.detach();

    std::thread t7(do_job, arr[6], filename);
    t7.detach();

    std::thread t8(do_job, arr[7], filename);
    t8.detach();
  }
  return 0;
}

Maybe it is not good way to solve my problem, but I`m only a beginner.

t.niese
  • 39,256
  • 9
  • 74
  • 101
  • Off topic but... the indentation in `SearchFile::find_file_in_directory` is misleading. The `if` and `else` clauses aren't grouped the way you think they are. Similarly for `SearchFile::find_file_from_directory` (and possibly others). – G.M. Aug 25 '20 at 09:21
  • Your while loop will keep spawning threads forever. Drop the loop, don't detach the threads, instead spawn them all first and then join them afterwards. – Botje Aug 25 '20 at 09:25
  • 2
    Even if code worked, filesystems perform best with sequential access (i.e. single-threaded). – rustyx Aug 25 '20 at 10:02

0 Answers0