Sobes.tech
Junior — Senior

Optimization of the multithreaded file path manager

livecode

Task condition

In the project, there is a class responsible for storing and providing file paths. The class receives lists of paths from different threads and must correctly handle requests from other threads. It is required to fix and improve the existing code without changing its external behavior.

Usage scenario:

  • One thread creates files on the server and passes their paths to the class object.
  • Another thread generates temporary files locally and also passes their paths.
  • Several additional threads retrieve the needed paths from the class (all files, only temporary and backup files, only regular files).

The task is to refactor and optimize the class to ensure correct operation in a multithreaded environment.

# include <vector>
# include <string>
# include <mutex>

using namespace std;

class temporaryGeneratedFilesObserver {
public:
    temporaryGeneratedFilesObserver(vector<string> f) {
        AddFiles(f);
    }

    void AddFiles(vector<string> f) noexcept {
        size_t i = f.size();
        try {
            m_mutex.lock();
            for (i = 0; i < f.size(); i++) {
                m_files.push_back(f[i]);
            }
            m_mutex.unlock();
        } catch (...) {
            m_files.erase(m_files.end() - i, m_files.end());
        }
    }

    vector<string> GetTempBackupFiles() {
        return GetFilesImpl(Backup | Temp);
    }

    vector<string> GetRegularFiles() {
        return GetFilesImpl(Regular);
    }

    vector<string> GetAllFiles() {
        return GetFilesImpl(All);
    }

private:
    enum Flags {
        Temp = 1,
        Backup = 2,
        Regular = 4,
        All = 7
    };

    vector<string> GetFilesImpl(uint32_t flags) {
        m_mutex.lock();

        vector<string> v = m_files;
        for (size_t i = 0; i < v.size(); i++) {
            if ((flags & Temp) && v[i].substr(v[i].size() - 4) == ".tmp") {
                v.erase(v.begin() + i--);
            }
            if ((flags & Backup) && v[i].substr(v[i].size() - 4) == ".bak") {
                v.erase(v.begin() + i--);
            }
            if ((flags & Regular) &&
                v[i].substr(v[i].size() - 4) != ".bak" &&
                v[i].substr(v[i].size() - 4) != ".tmp") {
                v.erase(v.begin() + i--);
            }
        }

        m_mutex.unlock();
        return v;
    }

    mutex m_mutex;
    vector<string> m_files;
};