具有 C++ 线程的并行字典破解器

Parallel dictionary cracker with c++ threads

我正在学习更好地使用 C++ 中的线程,这是我的学期末作业。我正在尝试创建一个相当简单的字典破解程序,它接受一个 .txt 文件并将每个单词复制到一个向量中;该向量被分成 "sectors" 等长(每个扇区的单词数)以便并行化。然后程序启动将 2 个迭代器作为参数的线程,指向一个扇区的开始和结束。每个线程在构造时将处理紧跟前一个的扇区。

因此,线程函数将遍历开始迭代器和结束迭代器之间的向量扇区的每个字,计算它的散列值,并将它与我需要破解的密码的散列值进行比较。我在实际访问迭代器指向的特定单词时使用了互斥体,尽管我不完全确定这是否是正确的方法。

目前,我的问题是出现了 2 个编译错误:

Error C2672 'std::invoke': no matching overloaded function found DictionaryCrackerEC d:\programs\microsoft visual studio 14.0\vc\include\thr\xthread 240

Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)' DictionaryCrackerEC d:\programs\microsoft visual studio 14.0\vc\include\thr\xthread 240

而且我不知道它们到底来自哪一行,也不知道如何解决。我在网上调查了各种 "invoke" 问题,但我要么不理解它们,要么它们似乎与 类 成员函数调用和类似的东西有关,而我什至没有 类 在我的程序中。

这就是理论,这是我主要的实际代码:

#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <fstream>
#include <chrono>
#include <Windows.h>
#include <assert.h>
#include <openssl\md5.h>
using namespace std;

//determine the best number of threads based on hardware
const int PC_THREADS_NUM = thread::hardware_concurrency();
mutex password_mutex;

int main()
{
    vector<string> passwdVector;
    vector<string>::const_iterator beginIter, endIter;
    passwdVector.reserve(18000);
    //code here that loads words from .txt file into passwdVector

    string userPassword = "";
    cout << "please insert the password that you'd like to crack: ";
    cin >> userPassword;

    //splitting the vector into sections to parallelize
    int sectionLength = passwdVector.size() / PC_THREADS_NUM;
    beginIter = passwdVector.begin();
    endIter = beginIter + sectionLength;
    vector<thread*> sliceHashingThreads;
    for (int i = 0; i < PC_THREADS_NUM; i++)
    {
        sliceHashingThreads.push_back(new thread(sliceHashCompare, std::ref(passwdVector), userPassword, beginIter, endIter, i));
        beginIter = endIter + 1;
        endIter += sectionLength;
    }
    for (int i = 0; i < sliceHashingThreads.size(); i++)
    {
        sliceHashingThreads[i]->join();
    }

    system("PAUSE");
    return 0;
}

这里是 sliceHashCoompare 函数:

    void sliceHashCompare(vector<string>& passwordList, string& password, vector<string>::const_iterator beginIter, vector<string>::const_iterator endIter, int& threadID)
{
    string vectorElement = "", hashedElement = "";
    bool isPassFound = false;
    while (isPassFound != true)
    {
        for (; beginIter <= endIter; ++beginIter)
        {
            password_mutex.lock();
            vectorElement = *beginIter;
            password_mutex.unlock();
            cout << threadID << " is processing word: " << vectorElement << endl;
            //Sleep(100);
            hashedElement = md5Hash(vectorElement);
            if(hashedElement == md5Hash(password))
            {
                isPassFound = true;
                cout << "The password was found! " << password << endl;
                cout << "Hash value: " << hashedElement << endl;
            }
        }
        if(isPassFound == false)
        {
            cout << "Password not found in the dictionary" << endl;
            break;
        }
    }
}

找到密码后,我想我需要一个条件变量来停止所有其他线程。我正在考虑的另一件事是稍后实现一个 farmer/worker 系统,它将向量分成更多更小的扇区,并有一个任务队列,以便在线程完成时继续为线程工作。但是现在我坚持使用 8 个线程 (thread::hardware_concurrency) 并且有些东西运行良好,我只会在之后进行改进。但非常感谢任何提示、建议和解释,因为我正在学习。

真的希望有人能向我解释出了什么问题,让我明白如何解决它以及为什么。非常感谢您的帮助!

我可以看到两个主要问题 - 你不能复制 std::thread,但你可以移动它,所以将它移动到你的向量中

sliceHashingThreads.push_back(
           std::move(new thread(sliceHashCompare,
                                std::ref(passwdVector),
                                userPassword,
                                beginIter,
                                endIter,
                                i)));

此外,请注意,如果您只是尝试调用您的函数,

sliceHashCompare(std::ref(passwdVector), userPassword, beginIter, endIter, 0);

你也会得到一个错误——因为它以threadID作为ref,如果你把它改成int threadID就可以了。

VS 给出了一个 "user friendly" 错误列表,但是如果您查看完整的输出(在视图 | 输出下找到),如果它还没有打开,那么搜索错误直到它提到您的代码。

现在应该可以编译 link。不过你还有其他问题。谁会删除你的话题?参见例如


当然,你不需要将指针移动到线程;问题是 int &(并没有删除指针)。

您可以通过使用 std::move

来使用 std::vector<std::thread>
sliceHashingThreads.emplace_back(sliceHashCompare, 
       std::ref(passwdVector),
       userPassword, beginIter, endIter, i);

您也可以使用 std::ref(i) 作为最后一个参数,以避免更改 sliceHashCompare 函数。