Multithreading 如何搜索下一个可用线程进行计算 我正在用C++做多线程。这可能是非常标准的东西,但我似乎在任何地方都找不到它,也不知道在网上搜索它的任何关键术语
我想做一些计算很多次,但有多个线程。对于每一次计算迭代,我想找到下一个可用线程,该线程已经完成了它的上一次计算,可以进行下一次迭代。我不想按顺序遍历线程,因为要调用的下一个线程可能尚未完成其工作 例如。 假设我有一个int向量,我想用5个线程加起来。我需要更新存储在某处的总金额,以及我当前使用的元素的计数。每个线程查看计数以查看下一个位置,然后获取该向量值并将其添加到目前为止的总和中。然后返回以查找计数以进行下一次迭代。因此,对于每个迭代,计数增量然后寻找下一个可用线程(可能是一个已经在等待计数的线程;或者它们都在忙于工作)来执行下一个迭代。我们不增加线程的数量,但我希望能够以某种方式搜索所有5个线程,找到第一个完成下一次计算的线程 我将如何编写这个。我所知道的每一种方法都涉及到在线程中执行循环,这样我就无法检查下一个可能出现故障的可用线程。在全局变量上使用semafor(或mutex,总是将这两个变量混在一起),告诉您下一个是什么。只要您访问变量,semafor就会锁定其他线程,从而清除线程访问 假设有一个X元素数组。一个名为nextfree的全局witch被初始化为0,则psudo代码如下所示:Multithreading 如何搜索下一个可用线程进行计算 我正在用C++做多线程。这可能是非常标准的东西,但我似乎在任何地方都找不到它,也不知道在网上搜索它的任何关键术语,multithreading,c++14,Multithreading,C++14,我想做一些计算很多次,但有多个线程。对于每一次计算迭代,我想找到下一个可用线程,该线程已经完成了它的上一次计算,可以进行下一次迭代。我不想按顺序遍历线程,因为要调用的下一个线程可能尚未完成其工作 例如。 假设我有一个int向量,我想用5个线程加起来。我需要更新存储在某处的总金额,以及我当前使用的元素的计数。每个线程查看计数以查看下一个位置,然后获取该向量值并将其添加到目前为止的总和中。然后返回以查找计数以进行下一次迭代。因此,对于每个迭代,计数增量然后寻找下一个可用线程(可能是一个已经在等待计数
while (1)
{
<lock semafor INT>
if (nextfree>=X)
{
<release semnafor INT>
<exit and terminate thread>
}
<Get the data based on "nextfree">
nextfree++;
<release semafor INT>
<do your stuff withe the chunk you got>
}
while(1)
{
如果(nextfree>=X)
{
}
nextfree++;
}
这里的要点是,每个线程都是单独的,并且对semafor锁中的数据结构具有独占访问权,因此,无论其他线程做什么,都可以访问下一个可用的数据结构。(其他线程如果完成了,则必须排队等待,而另一个线程正在获取下一个数据块。当您释放时,只有队列中的一个线程可以访问。其余线程必须等待。)
有些事情需要注意。如果您试图在错误的位置退出(释放它)或造成死锁,Semafor可能会锁定您的系统 这是一个线程池:
template<class T>
struct threaded_queue {
using lock = std::unique_lock<std::mutex>;
void push_back( T t ) {
{
lock l(m);
data.push_back(std::move(t));
}
cv.notify_one();
}
boost::optional<T> pop_front() {
lock l(m);
cv.wait(l, [this]{ return abort || !data.empty(); } );
if (abort) return {};
auto r = std::move(data.back());
data.pop_back();
return std::move(r);
}
void terminate() {
{
lock l(m);
abort = true;
data.clear();
}
cv.notify_all();
}
~threaded_queue()
{
terminate();
}
private:
std::mutex m;
std::deque<T> data;
std::condition_variable cv;
bool abort = false;
};
struct thread_pool {
thread_pool( std::size_t n = 1 ) { start_thread(n); }
thread_pool( thread_pool&& ) = delete;
thread_pool& operator=( thread_pool&& ) = delete;
~thread_pool() = default; // or `{ terminate(); }` if you want to abandon some tasks
template<class F, class R=std::result_of_t<F&()>>
std::future<R> queue_task( F task ) {
std::packaged_task<R()> p(std::move(task));
auto r = p.get_future();
tasks.push_back( std::move(p) );
return r;
}
template<class F, class R=std::result_of_t<F&()>>
std::future<R> run_task( F task ) {
if (threads_active() >= total_threads()) {
start_thread();
}
return queue_task( std::move(task) );
}
void terminate() {
tasks.terminate();
}
std::size_t threads_active() const {
return active;
}
std::size_t total_threads() const {
return threads.size();
}
void clear_threads() {
terminate();
threads.clear();
}
void start_thread( std::size_t n = 1 ) {
while(n-->0) {
threads.push_back(
std::async( std::launch::async,
[this]{
while(auto task = tasks.pop_front()) {
++active;
try{
(*task)();
} catch(...) {
--active;
throw;
}
--active;
}
}
)
);
}
}
private:
std::vector<std::future<void>> threads;
threaded_queue<std::packaged_task<void()>> tasks;
std::atomic<std::size_t> active;
};
模板
结构线程队列{
使用lock=std::unique_lock;
无效推回(T){
{
锁l(m);
数据。推回(std::move(t));
}
cv.通知_one();
}
boost::可选的pop_front(){
锁l(m);
wait(l,[this]{return abort | | |!data.empty();});
if(abort)返回{};
auto r=std::move(data.back());
data.pop_back();
返回std::move(r);
}
无效终止(){
{
锁l(m);
中止=真;
data.clear();
}
cv.通知所有人();
}
~u队列()
{
终止();
}
私人:
std::互斥m;
std::deque数据;
std::条件变量cv;
bool abort=false;
};
结构线程池{
线程池(std::size_t n=1){start_线程(n);}
线程池(线程池&&)=删除;
线程池&运算符=(线程池&&)=删除;
~thread_pool()=default;//或`{terminate();}`如果要放弃某些任务
模板
std::未来队列任务(F任务){
std::打包任务p(std::移动(任务));
自动r=p。获取未来();
任务。推回(std::move(p));
返回r;
}
模板
std::未来运行任务(F任务){
如果(线程数\活动线程数()>=总线程数()){
启动_线程();
}
返回队列_任务(std::move(task));
}
无效终止(){
tasks.terminate();
}
std::size\u t threads\u active()常量{
主动返回;
}
std::size\u t总线程数()常量{
返回线程。size();
}
无效清除_线程(){
终止();
线程。清除();
}
无效起始螺纹(标准::尺寸n=1){
而(n-->0){
把你推回去(
std::async(std::launch::async,
[本]{
while(auto task=tasks.pop_front()){
++活跃的;
试一试{
(*任务)();
}捕获(…){
--活跃的;
投掷;
}
--活跃的;
}
}
)
);
}
}
私人:
向量线程;
线程队列任务;
std::原子活性;
};
您可以在构造时或通过start\u-thread
为其指定线程数
然后,您将对任务进行排队
。这将返回一个std::future
,告诉您任务何时完成
当线程完成一项任务时,它们会进入线程化队列
并查找更多信息
当线程化_队列
被销毁时,它将中止其中的所有数据
当线程池
被销毁时,它将中止所有未来的任务,然后等待所有未完成的任务完成
.记录在案,求和一个
向量
对于通过工作线程协调任务来说是一个可怕的例子,工作线程急切地从一组公共值中提取;要做的工作量很小,而且同步以确保每个值只计算一次的成本很高。在这里,预先对数据进行分区更有意义,因为它消除了同步的需要(除了等待所有线程在合并结果之前完成),并使每个线程的数据访问模式可预测(适用于任何内存系统预取启发式)。