异步while循环的设计模式

时间:2013-05-14 10:40:08

标签: multithreading macos asynchronous grand-central-dispatch

我有一个归结为:

的功能
while(doWork)
{
  config = generateConfigurationForTesting();
  result = executeWork(config);
  doWork = isDone(result);
}

如果所有函数都是线程安全的,独立于以前的迭代,并且可能需要比最大允许线程数更多的迭代,我怎样才能重写这个以实现高效的异步执行?

这里的问题是我们不知道需要提前多少次迭代才能生成dispatch_group或使用dispatch_apply

这是我的第一次尝试,但由于任意选择的值和睡眠,它看起来有点难看;

int thread_count = 0;
bool doWork = true;
int max_threads = 20;  // arbitrarily chosen number

dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

while(doWork)
{
  if(thread_count < max_threads)
  {
    dispatch_async(queue, ^{ Config myconfig = generateConfigurationForTesting();
                             Result myresult = executeWork();
                             dispatch_async(queue, checkResult(myresult)); });
    thread_count++;
  }
  else
    usleep(100); // don't consume too much CPU
}

void checkResult(Result value)
{
  if(value == good) doWork = false;
  thread_count--;
}

2 个答案:

答案 0 :(得分:1)

根据您的描述,看起来generateConfigurationForTesting是某种随机化技术或者是一种可以进行近乎无限数量配置的生成器(因此您的评论提前您不知道如何你需要多次迭代)。以此为假设,您基本上坚持使用您创建的模型,因为您的执行程序需要受到关于队列的一些合理假设的限制,并且您不希望过度生成,因为这只会扩展成功找到value ==good测量值后的运行长度。

我建议您考虑使用队列(或OSAtomicIncrement*OSAtomicDecrement*)来保护对thread_countdoWork的访问权限。就目前而言,thread_count递增和递减将发生在两个不同的队列中(主线程的main_queue和后台任务的默认队列),因此可以同时递增和递减线程计数。这可能会导致计数不足(这会导致创建的线程数超出预期)或计入超量计数(这会导致您永远无法完成任务)。

使这个看起来更好一点的另一个选择是checkResult如果value!=good将新元素添加到队列中。这样,您可以使用dispatch_apply( 20, queue, ^{ ... })加载队列的初始元素,而根本不需要thread_count。前20个将使用dispatch_apply(或dispatch_apply认为适合您的配置的金额)添加,然后每次调用checkResult时,您可以设置doWork=false或向queue添加另一项操作。

答案 1 :(得分:1)

dispatch_apply()适用于此,只需传递ncpu作为迭代次数(apply永远不会使用超过ncpu工作线程)并保持工作块的每个实例运行,只要还有更多工作要做(即循环回generateConfigurationForTesting(),除非!doWork)。