我正在尝试将代码从单线程转换为多线程(例如,创建6个线程而不是1个线程),同时确保它们全部开始和结束而不会互相干扰。有什么方法可以做到这一点?我可以做一个for循环来创建线程,直到我<6吗?只需添加具有lock()和unlock()的互斥锁类?
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
void workerFunc()
{
boost::posix_time::seconds workTime(3);
std::cout << "Worker: running" << std::endl;
// Pretend to do something useful...
boost::this_thread::sleep(workTime);
std::cout << "Worker: finished" << std::endl;
}
int main(int argc, char* argv[])
{
std::cout << "main: startup" << std::endl;
boost::thread workerThread(workerFunc);
std::cout << "main: waiting for thread" << std::endl;
workerThread.join();
std::cout << "main: done" << std::endl;
system("pause");
return 0;
}
答案 0 :(得分:2)
是的,肯定有可能。由于您不希望它们之间有任何干扰,因此请为它们提供唯一的数据,以使您无需将对这些数据的访问与std::mutex
同步或使其成为std::atomic
。为了进一步减少线程之间的干扰,请根据std::hardware_destructive_interference_size对齐数据。
您可以使用boost::thread::hardware_concurrency()获取当前系统上可用的硬件线程数,这样就不必硬编码要运行的线程数。
可以使用std::ref
完成对线程的引用(否则线程将获得对数据副本的引用)。
在这里,我创建了一个std::list
线程和一个std::vector
数据以进行处理。
#include <cstdint> // std::int64_t
#include <iostream>
#include <list>
#include <new> // std::hardware_destructive_interference_size
#include <vector>
#include <boost/thread.hpp>
unsigned hardware_concurrency() {
unsigned rv = boost::thread::hardware_concurrency();
if(rv == 0) rv = 1; // fallback if hardware_concurrency returned 0
return rv;
}
// if you don't have hardware_destructive_interference_size, use something like this
// instead:
//struct alignas(64) data {
struct alignas(std::hardware_destructive_interference_size) data {
std::int64_t x;
};
void workerFunc(data& d) {
// work on the supplied data
for(int i = 0; i < 1024*1024-1; ++i) d.x -= i;
for(int i = 0; i < 1024*1024*1024-1; ++i) d.x += i;
}
int main() {
std::cout << "main: startup" << std::endl;
size_t number_of_threads = hardware_concurrency();
std::list<boost::thread> threads;
std::vector<data> dataset(number_of_threads);
// create the threads
for(size_t idx = 0; idx < number_of_threads; ++idx)
threads.emplace_back(workerFunc, std::ref(dataset[idx]));
std::cout << "main: waiting for threads" << std::endl;
// join all threads
for(auto& th : threads) th.join();
// display results
for(const data& d : dataset) std::cout << d.x << "\n";
std::cout << "main: done" << std::endl;
}
如果您使用的是C ++ 11(或更高版本),建议您改用std::thread
。
答案 1 :(得分:1)
std::vector<boost::thread> threads;
for (int i = 0; i < numberOfThreads; ++i) {
boost::thread t(workerFunc);
threads.push_back(std::move(t));
}
for (auto& t : threads) {
t.join();
}
请记住,join()
不会终止线程,只会等待线程完成。
Mutexe。您可以使用互斥锁来确保多个线程输入代码的关键部分。示例:
std::queue<int> q;
std::mutex q_mu;
void workerFunc1() {
// ...
{
std::lock_guard<std::mutex> guard(q_mu);
q.push(foo);
} // lock guard goes out of scope and automatically unlocks q_mu
// ...
}
void workerFunc2() {
// ...
{
std::lock_guard<std::mutex> guard(q_mu);
foo = q.pop();
} // lock guard goes out of scope and automatically unlocks q_mu
// ...
}
这可以防止发生不确定的行为,例如从队列中读取尚未完全写入的项目。小心-数据争用可能会使您的程序崩溃或损坏数据。我经常使用Thread Sanitizer或Helgrind之类的工具来确保我不会错过任何东西。如果只想将结果传递回主程序,而不需要在线程之间共享数据,则可以考虑使用std::promise
和std::future
。
答案 2 :(得分:0)
是的,可以通过一个简单的循环来生成新线程。不过,您将必须牢记以下几点:
int
也必须根据标准用原子或互斥体包裹)。join()
或detach()
,以防止其突然终止。