C ++ - 多线程需要更长的线程

问题描述 投票:-2回答:2

我正在为一项任务制作一个并行密码破解程序。当我启动多个线程时,破解所花费的时间越长,我添加的线程越多。这里有什么问题?

其次,我可以使用哪些资源共享技术来获得最佳性能?我还需要使用互斥量,原子操作或障碍,同时还要使用信号量,条件变量或通道。互斥体似乎会大大减慢我的程序。

以下是我的上下文代码示例:

std::mutex mtx;
std::condition_variable cv;

void run()
{
  std::unique_lock<std::mutex> lck(mtx);
  ready = true;
  cv.notify_all();
}

crack()
{
  std::lock_guard<std::mutex> lk(mtx);
  ...do cracking stuff
}

main()
{
  ....

  std::thread *t = new std::thread[uiThreadCount];

  for(int i = 0; i < uiThreadCount; i++)
  {
    t[i] = std::thread(crack, params);
  }

  run();

  for(int i = 0; i < uiThreadCount; i++)
  {
    t[i].join();
  }

}
c++ multithreading mutex
2个回答
1
投票

在编写多线程代码时,分享尽可能少的资源通常是个好主意,因此您可以避免使用mutexatomic进行同步。

密码破解有很多不同的方法,所以我给出一个稍微简单的例子。假设您有一个哈希函数和一个哈希值,并且您正在尝试猜测哪个输入产生了哈希值(这基本上是密码将被破解的方式)。

我们可以写这样的破解者。它将获取散列函数和密码散列,检查一系列值,并在找到匹配时调用回调函数。

auto cracker = [](auto passwdHash, auto hashFunc, auto min, auto max, auto callback) {
    for(auto i = min; i < max; i++) {
        auto output = hashFunc(i); 
        if(output == passwdHash) {
             callback(i);
        }
    }
};

现在,我们可以编写一个并行版本。此版本只有在找到匹配项时才需要进行同步,这种情况非常罕见。

auto parallel_cracker = [](auto passwdHash, auto hashFunc, auto min, auto max, int num_threads) {
    // Get a vector of threads
    std::vector<std::thread> threads;
    threads.reserve(num_threads);

    // Make a vector of all the matches it discovered
    using input_t = decltype(min); 
    std::vector<input_t> matches; 
    std::mutex match_lock;

    // Whenever a match is found, this function gets called
    auto callback = [&](input_t match) {
        std::unique_lock<std::mutex> _lock(match_lock); 
        std::cout << "Found match: " << match << '\n';
        matches.push_back(match); 
    };

    for(int i = 0; i < num_threads; i++) {
        auto sub_min = min + ((max - min) * i) / num_threads;
        auto sub_max = min + ((max - min) * (i + 1)) / num_threads;
        matches.push_back(std::thread(cracker, passwdHash, hashFunc, sub_min, sub_max, callback)); 
    }

    // Join all the threads
    for(auto& thread : threads) {
        thread.join(); 
    }
    return matches; 
};

0
投票

是的,编写它的方式并不奇怪:在你的线程的开头放一个互斥(crack函数),你有效地使它们按顺序运行

我知道你想要实现线程的“同步启动”(意图使用条件变量cv),但你没有正确使用它 - 没有使用它的wait方法之一,调用cv.notify_all()是没用的:它不按预期执行,而是您的线程将按顺序运行。

在你的wait()召唤中使用来自std::condition_variablecrack()势在必行:它将释放mtx(你刚刚用互斥卫士lk抓住)并将阻止执行该线程直到cv.notify_all()。在调用之后,你的其他线程(第一个除外,无论哪个)将保留在mtx下,所以如果你真的想要“并行”执行,那么你需要解锁mtx

在这里,你的crack线程应该如何:

crack()
{
  std::unique_lock<std::mutex> lk(mtx);
  cv.wait(lk);
  lk.unlock();

  ...do cracking stuff

}

顺便说一句,你在ready电话中不需要run()标志 - 它完全是冗余/未使用的。

我还需要使用互斥量,原子操作或障碍,同时还要使用信号量,条件变量或通道

- 不同的工具/技术对不同的东西有好处,问题太笼统了

© www.soinside.com 2019 - 2024. All rights reserved.