NTL:基本线程池
NTL:基本线程池
在坑了很久之后,今日琪琪子继续更新NTL技术文档。
从今天开始介绍NTL库的基本模块,首先介绍基本线程池。原始文档链接如下:https://shoup.net/ntl/doc/BasicThreadPool.cpp.html。
原文是以注释的形式将模块介绍了一下。
/******************************************************
模块名:基本线程池
简介:一个基本线程池类BasicThreadPool,以及某些更高级别的宏,这些宏可以支持简单的循环并行
*******************************************************/
/*******************************************************
基本的循环并行:
我们首先描述更高级别的宏,我们可以使用这些宏来写一些简单的并行化的循环。仅当我们设置了NTL_THREAD_BOOST=on的时候才有效(此时意味着NTL_THREADS=on)。 不过即便我们设置了NTL_THREAD_BOOST=off,使用这里介绍的工具进行编码也是能够正确的编译并且运行的, 所以这里是在所有的在编译时间和运行时环境下最简单的写并行循环的方式。我们得注意一下,如果NTL_THREADS=on, 要求C++11风格的代码,不过如果NTL_THREADS=off的话,就不需要这种编码风格了,所以C++11以下的编译器也能编译。
下面是一个简单的写并行循环的小例子。
在程序运行开始的时候,程序首先运行
SetNumThreads(nt)
我们可以选择nt为任意的正整数,但是为了达到最好的效果,nt取值应该对应于您的机器可用的核的数量。注意:如果已经设定了NTL_THREAD_BOOST=off,那么函数虽然被定义了, 但是不会起到任何作用。
现在我们考虑下面的循环。
void mul(ZZ* x,ZZ* a,zz* b,long n){
for(int i=0;i<n;i++){
mul(x[i],a[i],b[i]);
}
}
如果写成并行循环格式,可以这么写:
void mul(ZZ* x,const ZZ* a,const ZZ* b,const ZZ* c){
NTL_EXEC_RANGE(n,first,last){
for(long i=first;i<last;i++){
mul(x[i],a[i],b[i]);
}
NTL_EXEC_RANGE_END
}
}
NTL_EXEC_RANGE 以及 NTL_EXEC_RANGE_END都是宏,这两个宏会“做该做的事”。如果有nt个可用的线程,那么区间[0,n)就会最多被分割为nt个小区间,不同的线程会分别处理不同的子区间。人们仍然需要自己去写for循环,因为在宏里面仅仅声明并初始化循环中的第一个和最后一个long类型的变量,这些变量代表了第一个和最后一个在该线程中被处理的子区间的值。
我们得注意一下,当前的线程作为nt个可用的线程中的一个,当前线程会等待直到全部的线程结束任务之后再继续工作。当前线程可以被看做初始值为first==0的线程。
在该构造的构造内,我们可以*的引用在当前点可见的变量。这是使用C++的lambda特征完成的(使用引用来捕获全部的变量)。
我们得注意到在EXEC_RANGE范围内的代码可以调用其他尝试执行EXEC_RANGE的过程:如果这一点出现了,那么后边的EXEC_RANGE可以检测到这一点,并且在这种情况下,切换到单线程运行。
你可能会希望在EXEC_RANGE内部做一些除了循环之外其他的事情,比如声明变量这种。另外一个你可能想要做的事情就是为ZZ_p模块设置本地环境(或者为另外一个模块设置本地环境),下面就给出其中一个例子。
void mul(ZZ_p* x,const ZZ_p* a,const ZZ_p *b,long n){
ZZ_pContext context;
context.save();
NTL_EXEC_RANGE(n,first,last)
context.restore()
for(long i=first;i<last;i++){
mul(x[i],a[i],b[i]);
}
NTL_EXEC_RANGE_END
}
********************************************************/
上一篇: Linux下禁用Firefox浏览器的静默请求教程
下一篇: java基本线程机制