将唯一源分配给 C 中的线程池

Assigning unique sources to a thread pool in C

我用这个 library 创建了 pthread 的排队池。线程由 OS 决定,但我们知道只要队列已满,我们总是同时有 4 个作业(在下面的例子中)运行。

如果每个作业使用 4 个可用源中的一个源,我想保证同时使用所有 4 个源。避免一个源被使用两次而另一个源一次不用。

我想到了这个想法,即使用一个数组来跟踪使用过的资源

#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#include "thpool.h"

int sources[4] = {0}; // 0 Source is available 1 Source is occupied

void task(void *arg)
{
    int source;
    for (int i = 0; i < 4; i++)
    {
        if (sources[i] == 0)
        {
            sources[i] = 1; // Occupying the source
            source = i; // Assining the source
            break;
        }
    }
    sleep(1);
    printf("Thread %u working on %d with source %d\n", (int)pthread_self(), (int)arg, source);
    sources[source] = 0; // Making the source available again
}

int main()
{

    puts("Making threadpool with 4 threads");
    threadpool thpool = thpool_init(4);

    puts("Adding 40 tasks to threadpool");
    int i;
    for (i = 0; i < 40; i++)
    {
        thpool_add_work(thpool, task, (void *)(uintptr_t)i);
    };

    thpool_wait(thpool);
    puts("Killing threadpool");
    thpool_destroy(thpool);

    return 0;
}

这在基本测试中运行良好,但我不确定可靠性,因为我们没有锁定更新 sources 数组的过程。

在我看来,您是在重新发明轮子,但不幸的是,方法不对。 POSIX 线程 API 已经具有您正在寻找的功能:mutexes。只需定义 4 个互斥量并将它们用于 locking/unlocking 资源。

pthread_mutex_t locks[4] = {
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER
};

void task(void *arg) {
    pthread_mutex_t *lock;

    for (int i = 0; i < 4; i++) {
        lock = &locks[i];

        if (!pthread_mutex_trylock(lock))
            break;
    }

    // Work ...

    pthread_mutex_unlock(lock);
}

注意: 上面的代码只有在你总是有 最多 4 个线程 运行 同时(你提到您正在使用的库强制执行此规则,所以这应该没问题)。如果你有更多,上面的代码将无法从第 5 个线程开始锁定任何互斥量,然后将尝试解锁被另一个线程锁定的互斥量,这是非常糟糕的。在这种情况下,您需要将 for 循环包装到 while (1) 中,或者想出一个稍微复杂一点的不同解决方案,例如使用条件或信号量。