1

为了解决一个问题(以及更好地理解多任务处理),我编写了一个小型线程池实现。这个线程池启动了一些工作线程,当线程池的客户端添加任务时,这些线程会从队列中弹出任务。出于此问题的目的,当任务队列为空时,工作线程全部终止。

在做了一些基本的基准测试之后,我发现应用程序花费了大约 60% 的时间来等待获取队列锁。大概这主要发生在工作线程中。

这仅仅是表明我没有给工作线程足够的工作,还是更多?我可能缺少一些简单的东西来增加工作线程的吞吐量吗?

编辑:这是一些粗略的伪代码,应该可以说明一些事情。这是在工作线程执行期间获取/释放锁的仅有的两个地方(这是应用程序运行时间的绝大部分。)

std::list<task_t> task_list;

// Called by the client to add tasks to the thread pool
void insert_task(const task_t& task)
{
    lock_type listlock(task_mutex);

    task_list.push_back(task);
}

// The base routine of each thread in the pool. Some details
// such as lifetime management have been omitted for clarity.
void worker_thread_base()
{
    while (true)
    {
        task_t task;

        {
        lock_type listlock(task_mutex);

        if (task_list.empty())
            continue;

        task = task_list.front();

        task_list.pop_front();
        }

        do_task(task);
    }
}
4

2 回答 2

0

您是否尝试使用单个锁、多个锁来执行此操作?互斥体?您使用的是什么等待语义?

我会从你的描述中猜测(这纯粹是猜测)你有类似的东西:

lock(theLock) {
 // ... do lots of work ...
}

在包含要分派到轻量级线程的代码的主线程中。您可能会看到等待时间延长的一个原因是,您需要从已启动的线程返回信号,表明它们已排队等待执行(这也是一个猜测,因为您没有提供任何代码)。

您可以解决此问题的一种方法是从使用显式锁定(如上所述)切换到使用信号互斥锁,当您希望其中一个线程获取工作时,该互斥锁会发出脉冲。

但是,如果没有看到您当前的实现,我不确定我是否可以超越这一点。

于 2010-08-05T17:23:53.890 回答
0

您的设计构建在每个线程所在的位置并“旋转”试图获取锁。这将不断发生,除非每个工作线程都在执行工作——在这种情况下,锁将不会被获取并且工作将会发生。

由于您的所有线程都只是坐着,在锁上旋转,您将使用相当多的 CPU 时间等待。考虑到您的设计,这在某种程度上是意料之中的。

您会发现,如果您的工作线程较少,阻塞的时间百分比可能会显着减少 - 在您拥有的工作项多于线程的地方,您将花费很少的时间等待该锁。

更好的设计是为您的工作队列使用某种形式的无锁队列,因为这可以防止此时等待。此外,拥有一个可以阻塞工作线程直到队列中有工作的等待句柄将防止不必要的旋转。

于 2010-08-05T17:39:28.347 回答