我有一个C程序,它创建两个线程(除了main(,T1和T2。T1执行发出操作O1的功能,T2执行发出操作〈em>O2
void* f1() {
O1();
var = 0;
}
void* f2() {
O2();
var = 1;
}
int main(int argc, char **argv){
pthread_t t1, t2;
int var;
pthread_create(&t1, NULL, &f1, NULL);
pthread_create(&t2, NULL, &f2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("var = %dn", var);
return 0;
}
CCD_ 1和CCD_。该程序的目的是在两个线程都完成执行后,通过检查var
的值来检查哪个操作更快。这将要求O1((和O2((在两个核心上同时并行运行(或者以几个周期的数量级存在非常轻微的可容忍差异(。我该如何确保这一点?
编辑:根据Peter Cordes的建议,我修改了f1()
和f2()
,以读取O1()
和O2()
同步执行的时间戳。
void* f1() {
t1 = rdtsc();
while(t1 != 0){
t1 = rdtsc();
}
printf("t1 = %dn", t1);
O1();
var = 0;
}
void* f2() {
t2 = rdtsc();
while(t2 != 0){
t2 = rdtsc();
}
printf("t2 = %dn", t2);
O2();
var = 1;
}
然而,t2
在控制台上打印的时间远远晚于t1
。我想这表明t1
0已经在f2()
中循环到0,并且没有导致O1()
和O2()
的同步执行。线程屏障没有提供我所要求的同步粒度。
f1
和f2
在大多数平台上的实际调用中肯定会有很小的延迟,但延迟取决于硬件、操作系统(OS(,尤其是其调度程序。从理论上讲,不可能保证这两个功能在所有平台上总是同时启动。事实上,操作系统调度器可以自由地调度同一核心上的线程,即使您将线程绑定到核心,线程也可以随时中断(例如,由更高优先级的任务中断(。此外,在大多数现代处理器上,核心时钟并不强同步。也就是说,在实践中,屏障显然足以使函数大致同时运行(在大多数系统上,粒度接近几微秒,甚至更少(。Pthread提供了这样的特性(例如,请参见pthread_barrier_init
和pthread_barrier_wait
(。请注意,可能需要旋转等待以获得更好的精度(通常为1-10ns,可能与硬件有关(。AFAIK不可能以比x86处理器几十个周期更好的精度同步线程。这是因为现代处理器以并行和无序的方式运行指令,具有相当长的复杂管道,并且任何核心间同步都特别慢(通常是因为要走的路径很长、缓存一致性协议和基本物理定律(。
确定O1((或O2((是否更快的最准确方法是对每种方法进行基准测试。有非常准确的方法可以测量运行时间,当然,运行O1((几次,然后运行O2((几遍,并记录启动/停止时间,会给出准确的平均答案。平均值中包含的运行次数越多,结果就越准确,结果的标准偏差也就越确定。
依靠操作系统以某种方式即时启动线程并不是很好。无法保证操作系统在第一个线程启动后会运行main((;有些操作系统会让新创建的线程运行一段时间,而不是它的创建线程,只是为了看看它是否能快速完成(有些确实如此(。