我想用pthread实现分而治之,但是我不知道如果我在一个线程中创建更多的线程会发生什么。
据我所知,如果机器有2核处理器,它只能同时处理2个线程。如果有2个以上的线程,其他线程必须等待资源,所以如果我在更深的地方创建越来越多的线程,实际上可能不会提高算法的速度,因为同时只能处理2个线程。
我在网上做了一些研究,似乎上层的线程可能是不活跃的,只有最深层的线程才保持活跃。如何做到这一点?另外,如果上层线程保持非活动状态,是否会影响底层线程?
发布于 2012-05-15 18:06:47
有两种基本类型:分离的和可接合的。
可接合线程是您可以使用pthread_join等待(或访问)终止的线程。
使用比核心更多的线程可能会有帮助,也可能会有坏处--这取决于您的程序!使用多线程来最小化或消除对资源的竞争通常是有好处的。在一个程序中抛出太多的线程实际上会减慢进程。但是,如果内核数量与线程计数相匹配,并且其中一个线程正在等待磁盘IO (假设其他进程中没有发生重大事件),则可能会有空闲的CPU时间。
较高级别的
线程可以处于非活动状态,只有最深级别的线程才保持活动状态。如何做到这一点?
使用可接合线程,您可以完成您概述的嵌套线程方法,这在几个教程中进行了演示。基本流程是,线程将创建一个或多个工作进程,并使用pthread_join等待它们退出。但是,在大多数情况下,任务和线程池等替代方案更可取。
然而,这种方法不太可能是最好的执行方法,因为它不能(很好地)与硬件和调度操作相关联,特别是随着程序的深度和宽度的增长。
如果上层线程保持不活动,是否不会影响下层线程?
是。然而,典型的问题是工作/线程不受约束。使用您概述的方法,很容易产生许多线程,并且对于必须在有限数量的内核上执行的工作来说,具有不合理的高线程数量。因此,您的程序将浪费大量时间进行上下文切换和等待线程完成。创建多个线程也会浪费/保留大量资源,特别是如果它们是短暂的和/或空闲/等待的。
,所以如果我创建越来越多的线程,同时深入到更深的地方,实际上它可能不会增加算法的速度,因为同时只能处理2个线程。
这表明使用这种方法创建线程是有缺陷的。您可能希望创建几个线程,并使用基于任务的方法--其中每个线程请求并执行集合中的任务。创建线程需要花费大量的时间和资源。
发布于 2012-05-15 18:45:02
如果你正在尝试做一个双向的分而治之,产生两个孩子并等待他们完成,你可能需要这样的东西:
void *
routine (void * argument)
{
/* divide */
left_arg = f (argument);
right_arg = f (argument);
/* conquor */
pthread_create (left_child, NULL, routine, left_arg);
pthread_create (right_child, NULL, routine, right_arg);
/* wait for 'children' */
pthread_join (left_child, &left_return_val);
pthread_join (right_child, &right_return_val);
/* merge results & return */
}一个轻微的改进是,“父线程”不是休眠,而是同步地完成正确的子线程的工作,并少产生一个线程:
void *
routine (void * argument)
{
/* divide */
left_arg = f (argument);
right_arg = f (argument);
/* conquor */
pthread_create (left_child, NULL, routine, left_arg);
/* do the right_child's work yourself */
right_return_val = routine (right_arg);
/* wait for 'left child' */
pthread_join (left_child, &left_return_val);
/* merge results & return */
}然而,当你深入到N层时,你会有相当多的孩子。获得的加速比实际上取决于CPU在实际处理上花费了多少时间,以及它等待I/O的时间等。如果你知道在有P内核的机器上,你只能通过kP线程获得良好的加速比,那么你可以设置一个kP线程的“worker pool”,并不断地重用它们,而不是像上面那样产生线程。这样,一旦产生了kP线程,就不会产生更多的线程:
THREAD_POOL pool = new_thread_pool (k * P); /* I made this function up */
void *
routine (void * argument)
{
/* divide */
left_arg = f (argument);
right_arg = f (argument);
/* conquor */
left_thread = get_worker (pool); /* Blocks until a thread is free */
/* get left_thread to do processing for you */
right_thread = get_worker (pool); /* Blocks until a thread is free */
/* get right_thread to do processing for you */
/* wait for 'children' */
pthread_join (left_child, &left_return_val);
pthread_join (right_child, &right_return_val);
/* return the workers */
put_worker (pool, left_thread);
put_worker (pool, right_thread);
/* merge results & return */
}发布于 2012-05-15 18:10:37
您应该能够创建比系统中的内核多得多的线程。操作系统将确保每个线程都让CPU的一部分来完成它的工作。
但是,您可以创建的线程数可能有一个上限(请查看您的操作系统文档)。
因此,如果您在一个具有2个核心的系统中创建5个线程,那么每个线程将获得大约40%的cpu (平均)。这并不是说一个线程必须等到另一个线程完全完成。当然,除非你使用锁。
当您使用锁来保护数据不被多线程更改或访问时,可能会出现许多问题。典型问题包括:
我找到了这个页面(http://ashishkhandelwal.arkutil.com/index.php/csharp-c/issues-with-multithreaded-programming-part-1/),它可能是多线程编程的一个很好的开端。
https://stackoverflow.com/questions/10598303
复制相似问题