如何从另一个函数内的随机位置调用C函数?

谁能告诉我如何在C函数内的随机位置插入函数调用(比如Yield() ),这样每次运行代码时,从代码的不同部分调用Yield()

我面临着这样的要求:我在协作线程环境中使用2个线程,除非正在运行的线程明确地产生处理器,否则另一个(等待)线程无法开始运行。 我不想将Yield()调用放在单个点上,因为这会使线程序列具有确定性。 如果不重新布线整个环境(从合作到先发制人),这是我能想到的唯一解决方案,Thread_1()在其中的随机位置调用Yield() ,允许Thread_2()接管。

对于达到相同目标的不同解决方案的任何见解也是受欢迎的!

我想要一个BFI解决方案

我想你必须以明显的方式解决这个问题。 你需要为Yield()做一个包装器,它会决定是否调用真实的东西。

如果你不关心执行速度那么我会把它变成一个真正的C函数,如果你是我可能会建议一个预处理器宏。

所以,像:

 #define Yield0() ((random() & 0xf) == 0 && Yield()) 

选择所需通话百分比的掩码。 对于0xf,如果random()具有良好的低阶位随机性,那么在16次调用中你会看到1 Yield()。 如果你可以使用MT或其他高质量的随机数发生器,低阶位将直接有用,否则你可能想要random() >> 3 & ...

而你只需要在任何地方放置Yield0()调用。

我定义了一个函数:

 void maybe_yield() { if (rand() & 0x10) yield(); } 

然后在整个代码中调用maybe_yield() 。 根据您希望调用yield的频率,您可以将0x10更改为常量,并设置更多位以更频繁地调用yield() 。 除此之外,一定要调用srand() ,其值从一次运行变为另一次运行,以便在不同的运行中获得不同的序列。

选项A:为什么不在线程卡住时调用yield() ? 更好的是,为什么不在可能卡住的每个操作中封装它:

 int disk_read (...) { begin_io (); while (!io_completed && !timed_out()) yield(); if (timed_out()) // etc. ... } 

选项B:通常 – 合作屈服 – 当另一个线程未准备好运行时, yield()是无操作。 因此,把它放在任何地方:

 void thread1 (...) { yield(); do_something_a(); yield(); do_something_b(); yield(); do_something_c(); ... } 

选项C:相信处理器速度很快并且等待事情经常发生,以至于最小的yields()工作得很好:

 void thread1 (...) { init(); while (...) { do_heavy_crunching(); yield(); do_something_else(); } } 

在数百个实际应用程序中,Option C工作正常。 决定论通常有帮助,而不是伤害。

实际上,当你在一个合作的线程环境中运行时,你确实需要确定性。

但是,如果你一心想做它,你只需要让它随机。

 #include  // And make sure you seed the generator with srand() somewhere. #define YIELD_CHANCE 15 #define yield Yield #ifdef YIELD_CHANCE #if YIELD_CHANCE > 0 #if YIELD_CHANCE <= 100 #undef yield void yield(void) { if (rand() < (RAND_MAX / (100/YIELD_CHANCE))) Yield(); } #endif #endif #endif 

然后将Yield调用更改为yield并且根据YIELD_CHANCE在编译时设置的值,您将获得确定性或非确定性行为。

如果它不存在或超出1到100的范围,则yield将一直产生。 如果它在该范围内,那么它将根据您给出的概率随机调用Yield函数。

你说你不想要一个预处理器,但它让它变得如此简单。

  #!/usr/bin/perl chomp(my $n =); open (my $f, '<', $n); while (my $l = <$f>) { print $l; if ($l =~ /^[\s][^\.]/) { $r=rand(); if ( int($r*5) == 1 ) { print "\tcall Yield\n"; } } } 

这个perl脚本(我的第一个)将从stdin中读取文件名并随机插入一个调用gcc -S生成的程序集,然后可以轻松编译。 它可能不适用于您的编译器/ arch,但正则表达式几乎可以做任何事情。

一个很好的补充是在处理器的跳转指令之前总是增加一个良率。 这可以节省您的喷洒。 最后在跳转之前,您可以使用调用random()的包装函数。