首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Cilk Plus中组织非线程安全资源池(每个工作人员一个资源)?

如何在Cilk Plus中组织非线程安全资源池(每个工作人员一个资源)?
EN

Stack Overflow用户
提问于 2015-07-19 12:12:57
回答 1查看 124关注 0票数 1

我有一个使用calls并行化的串行代码;主循环在不同的数据集上反复调用一个处理函数,因此迭代是相互独立的,除了使用一个非线程安全的资源外,该资源被封装到外部库提供的类(例如nts)中,该类接受文件名并在其上执行I/O操作。

如果我使用的是OpenMP,我将创建一个资源池,其中包含的资源与我拥有的线程一样多,并根据线程ID访问这些资源:

代码语言:javascript
复制
std::vector<nts> nts_pool;
for (std::size_t i{0}; i < omp_get_num_threads(); ++i)
    nts_pool.push_back(nts{});

nts_pool[omp_get_thread_num()].do_stuff();  // from inside the task

使用Cilk,我可以使用__cilkrts_get_nworkers()__cilkrts_get_worker_number() API做同样多的事情,但是从英特尔论坛上的多篇文章中,我发现这是一个错误的问题解决方案,正确的解决方案应该是使用holder超级对象。

现在,holder解决方案看起来确实不错,只不过我真的希望创建的视图与我有工作线程的视图一样多。也就是说,对于3个工作线程,我希望有3个对象,而不是更多。理由是,正如我所说的,资源是由第三方库提供的,构建起来非常昂贵,之后我将不得不处理结果文件,所以越少越好。

不幸的是,我发现,与其为每个工作人员创建一个视图并保持其同步,还不如通过某种方式创建和销毁视图,这是我所不理解的逻辑,而且似乎没有办法影响这种行为。

是否有可能让持卡人以我想要的方式行事,如果没有,什么是解决我的问题的惯用的Cilk Plus解决方案?

下面是我用来调查持卡人的程序,请注意,它在一次运行中在我的测试机器上创建了多达50个视图,这些视图似乎是随机分配和销毁的:

代码语言:javascript
复制
#include <iostream>
#include <atomic>

#include <cilk/cilk.h>
#include <cilk/holder.h>
#include <cilk/reducer_ostream.h>
#include <cilk/cilk_api.h>

cilk::reducer_ostream *hyper_cout;

class nts {
public:
    nts() : tag_{std::to_string(++id_)} {
        *hyper_cout << "NTS constructor: " << tag_ << std::endl;
    }
    ~nts() {
        *hyper_cout << "NTS destructor: " << tag_ << std::endl;
    }
    void print_tag() {
        *hyper_cout << "NTS tag: " << tag_ << std::endl;
    }
    static void is_lock_free() {
        *hyper_cout << "Atomic is lockfree: " << id_.is_lock_free() << std::endl;
    }
private:
    const std::string tag_;
    static std::atomic_size_t id_;
};

std::atomic_size_t nts::id_{0};

class nts_holder {
public:
    void print_tag() { nts_().print_tag(); }
private:
    cilk::holder<nts> nts_;
};

int main() {

    __cilkrts_set_param("nworkers", "4");

    cilk::reducer_ostream cout{std::cout};
    hyper_cout = &cout;

    *hyper_cout << "Workers: " <<  __cilkrts_get_nworkers() << std::endl;
    nts::is_lock_free();

    nts_holder ntsh;
    ntsh.print_tag();

    for (std::size_t i{0}; i < 1000; ++i) {
        cilk_spawn [&] () {
            ntsh.print_tag();
        } ();
    }

    cilk_sync;

    return 0;

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-21 16:00:11

你是正确的,持有人是一个诱人但低效的解决办法,这个特定的问题。如果您的程序正确地使用了每个工作人员一个插槽的插槽数组,那么在本例中使用__cilkrts_get_nworkers()__cilkrts_get_worker_number() API并没有错。我们确实不鼓励它们的普遍使用;我们更喜欢编写Cilk代码,它忽略了数字工作者,因为它通常以这种方式扩展得更好。但是,有些情况下,包括这种情况,为每个员工创建一个槽是最好的策略。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31501065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档