Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;重用调用相同函数的线程向量_C++_Multithreading_C++14_Threadpool_Stdthread - Fatal编程技术网

C++ C++;重用调用相同函数的线程向量

C++ C++;重用调用相同函数的线程向量,c++,multithreading,c++14,threadpool,stdthread,C++,Multithreading,C++14,Threadpool,Stdthread,我想重用线程向量,这些线程使用不同的参数多次调用同一个函数。不需要写入(原子参数除外),因此不需要互斥。为了描述这个想法,我创建了一个并行化代码的基本示例,用于查找向量的最大值。显然有更好的方法来求向量的最大值,但是为了解释和避免深入了解我正在编写的实际代码的细节,我将使用这个愚蠢的示例 代码通过调用函数pFind查找向量的最大数目,该函数检查向量是否包含数字k(k用上限初始化)。如果执行,则停止执行,否则k将减少1并重复该过程 下面的代码生成一个线程向量,并行搜索向量中的k。问题在于,对于k的

我想重用线程向量,这些线程使用不同的参数多次调用同一个函数。不需要写入(原子参数除外),因此不需要互斥。为了描述这个想法,我创建了一个并行化代码的基本示例,用于查找向量的最大值。显然有更好的方法来求向量的最大值,但是为了解释和避免深入了解我正在编写的实际代码的细节,我将使用这个愚蠢的示例

代码通过调用函数pFind查找向量的最大数目,该函数检查向量是否包含数字kk用上限初始化)。如果执行,则停止执行,否则k将减少1并重复该过程

下面的代码生成一个线程向量,并行搜索向量中的k。问题在于,对于k的每个值,线程向量都会重新生成,并且每次新线程都会被连接。 生成线程向量并每次连接它们会带来我想要避免的开销

我想知道是否有一种方法可以只生成一次线程向量(一个池)并在新的执行中重用它们。任何其他加速提示将不胜感激

void pFind(
    vector<int>& a,
    int n,
    std::atomic<bool>& flag,
    int k,
    int numTh,
    int val
    ) {
    int i = k;

    while (i < n) {
        if (a[i] == val) {
            flag = true;
            break;
        } else 
            i += numTh;
    }
}

int main() {   
    std::atomic<bool> flag;
    flag = false;
    int numTh = 8;
    int val = 1000;
    int pos = 0;

    while (!flag) {
        vector<thread>threads;
        for (int i = 0; i < numTh; i++){ 
            thread th(&pFind, std::ref(a), size, std::ref(flag), i, numTh, val);
            threads.push_back(std::move(th));
        }
        for (thread& th : threads) 
            th.join();

        if (flag) 
           break;

        val--;

   }
   cout << val << "\n";
   return 0;
}
void pFind(
向量&a,
int n,
标准::原子和标志,
int k,
整数,
int val
) {
int i=k;
而(icout您的代码具有竞争条件:
bool
不是原子类型,因此多个线程并发写入不安全。您需要使用或

为了回答您的问题,您正在为循环的每次迭代重新创建
线程
向量,您可以通过将其声明移到循环体之外来避免这种情况。重用线程本身是一个更为复杂的主题,很难正确或简洁地描述

vector<thread> threads;
threads.reserve(numTh);

while (!flag) {
    for (size_t i = 0; i < numTh; ++i)
        threads.emplace_back(pFind, a, size, flag, i, numTh, val);
    for (auto &th : threads)
        th.join();
    threads.clear();
}
向量线程;
线程保留(numTh);
while(!flag){
对于(尺寸i=0;i
无法分配不同的执行功能(关闭)在构造后对
std::thread
。这通常适用于所有线程抽象,尽管通常实现会尝试在内部记忆或缓存较低级别的抽象,以使线程分叉和连接速度更快,因此仅构造新线程是可行的。在系统编程界,关于是否创建新线程存在争议read应该是非常轻量级的,或者客户端是否应该像fork线程那样频繁地被写入(考虑到这种情况已经持续了很长时间,应该很清楚,这涉及到很多折衷)

还有很多其他的抽象,它们试图做你真正想做的事情。它们的名字有“线程池”、“任务执行者”(或者只是“执行者”)和“未来”它们都倾向于通过创建一组线程(通常与系统中硬件内核的数量有关)映射到线程,然后让每个线程循环并查找请求

如注释所示,您自己这样做的主要方式是让线程具有顶级循环,该循环接受执行请求,处理它们,然后发布结果。要做到这一点,您需要使用其他同步方法,如互斥体和条件变量。如果有,通常这样做会更快很多请求和请求都不是非常大


标准C++的并发支持是一件好事,它也相当缺乏现实世界高性能的工作。类似的是更为工业化的解决方案。

< p>通过拼凑来自不同在线搜索的一些代码,下面的工作,但是是<>强>不快> <强> >它在while循环的每次迭代中重新生成线程

也许有人可以对这种方法发表评论

下面的类描述线程池

class ThreadPool {
    public:
    ThreadPool(int threads) : shutdown_(false){
        threads_.reserve(threads);
        for (int i = 0; i < threads; ++i)
           threads_.emplace_back(std::bind(&ThreadPool::threadEntry, this, i));
    }

    ~ThreadPool(){
        {
            // Unblock any threads and tell them to stop
            std::unique_lock<std::mutex>l(lock_);

            shutdown_ = true;
            condVar_.notify_all();
        }

        // Wait for all threads to stop
        std::cerr << "Joining threads" << std::endl;

        for (auto & thread : threads_) thread.join();
    }

    void doJob(std::function<void(void)>func){
        // Place a job on the queu and unblock a thread
        std::unique_lock<std::mutex>l(lock_);

        jobs_.emplace(std::move(func));
        condVar_.notify_one();
    }

    void threadEntry(int i){
        std::function<void(void)>job;

        while (1){
            {
                std::unique_lock<std::mutex>l(lock_);

                while (!shutdown_ && jobs_.empty()) condVar_.wait(l);

                if (jobs_.empty()){
                    // No jobs to do and we are shutting down
                    std::cerr << "Thread " << i << " terminates" << std::endl;
                    return;
                }

                std::cerr << "Thread " << i << " does a job" << std::endl;
                job = std::move(jobs_.front());
                jobs_.pop();
            }

            // Do the job without holding any locks
            job();
        }
   }
};
类线程池{
公众:
线程池(int线程):关闭(false){
螺纹预留(螺纹);
对于(int i=0;i通常,您编写的任务处理器使用从队列中提取的参数执行给定任务;主线程填充共享的参数队列,工作人员根据需要从中提取新工作。您需要访问队列的互斥体,但前提是插入和提取工作项的成本较低(使用
.front()
std::move
以避免在
.pop()
之后进行复制构造以删除该项,而所有其他工作都不在互斥锁的控制范围内,或者如果
std::move
仍然非常昂贵,存储和检索
unique\u ptr
或类似内容),锁争用应该是最小的
void pFind(
vector<int>& a,
int n,
std::atomic<bool>& flag,
int k,
int numTh,
int val,
std::atomic<int>& completed) {
    int i = k;

    while (i < n) {
        if (a[i] == val) {
            flag = true;
            break;
        } else 
            i += numTh;
    }
    completed++;
}

int main() {   
    std::atomic<bool> flag;
    flag = false;
    int numTh = 8;
    int val = 1000;
    int pos = 0;
    std::atomic<int> completed;
    completed=0;

    ThreadPool p(numThreads);

    while (!flag) {
        for (int i = 0; i < numThreads; i++) {
            p.doJob(std::bind(pFind, std::ref(a), size, std::ref(flag), i, numTh, val, std::ref(completed)));
        }

        while (completed < numTh) {}

        if (flag) {
            break;
        } else {
            completed = 0;
            val--;
        }

   }
   cout << val << "\n";
   return 0;
}