我正在为任务分配并行密码破解程序。当我启动多个线程时,我添加的线程越多,破解所需的时间就越长。这里有什么问题?
第二,我还可以使用哪些资源共享技术来获得最佳性能?我需要使用互斥体,原子操作或障碍,同时还需要使用信号量,条件变量或通道。互斥体似乎大大降低了我的程序速度。
这是我的上下文代码示例:
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();
}
}
答案 0 :(得分:1)
编写多线程代码时,通常最好共享尽可能少的资源,因此您可以避免必须使用mutex
或atomic
进行同步。
有很多不同的方法来进行密码破解,因此,我将给出一个更简单的示例。假设您有一个散列函数和一个散列,并且您试图猜测是什么输入产生了散列(这基本上就是破解密码的方式)。
我们可以这样写饼干。它将使用哈希函数和密码哈希,检查值的范围,如果找到匹配项,则调用回调函数。
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;
};
答案 1 :(得分:0)
是的,它的编写方式不足为奇:将互斥锁放在线程的开头(crack
函数),可以有效地使它们按顺序运行
我知道您想实现线程的“同步启动”(通过使用条件变量cv
的意图),但是您使用的方式不正确-如果不使用其{{1 }}方法中,调用wait
是无用的:它并没有达到您的预期,相反,您的线程只会按顺序运行。
在您的cv.notify_all()
调用中使用wait()
中的std::condition_variable
是必不可少的:它将释放crack()
(您刚刚被互斥防护mtx
抓住了),并会阻塞线程的执行,直到lk
。调用之后,您的其他线程(第一个线程除外,无论哪个线程)都将保留在cv.notify_all()
下,因此,如果您确实希望执行“并行”执行,则需要解锁{{1} }。
在这里,您的mtx
线程应如下所示:
mtx
顺便说一句,您在crack
调用中不需要crack()
{
std::unique_lock<std::mutex> lk(mtx);
cv.wait(lk);
lk.unlock();
...do cracking stuff
}
标志-它完全是多余的/未使用的。
我必须使用互斥体,原子操作或障碍 同时还使用信号量,条件变量或通道
-不同的工具/技术对不同的事物都有好处,这个问题太笼统了