将唯一源分配给 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)
中,或者想出一个稍微复杂一点的不同解决方案,例如使用条件或信号量。
我用这个 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)
中,或者想出一个稍微复杂一点的不同解决方案,例如使用条件或信号量。