Шаблон выглядит как довольно стандартный пул потоков:
typedef struct {
pthread_mutex_t qlock;
pthread_cond_t q_not_empty;
volatile work_t *qhead;
volatile work_t *qtail;
size_t qsize; /* Not needed */
volatile int shutdown;
} threadpool;
Правильный отступ кода OP делает его более читабельным.
Однако реализация выглядит странно. Я бы ожидал
void *do_work(void *poolptr)
{
threadpool *const pool = poolptr;
work_t *work;
pthread_mutex_lock(&(pool->qlock));
while (!(pool->shutdown)) {
if (!(pool->qhead)) {
/* Queue empty */
pthread_cond_wait(&(pool->q_not_empty), &(pool->qlock));
continue;
}
work = pool->qhead;
pool->qhead = work->next;
if (!pool->qhead)
pool->qtail = NULL;
work->next = NULL;
pthread_unlock(&(pool->qlock));
work->process(work);
pthread_lock(&(pool->qlock));
}
pthread_mutex_unlock(&(pool->qlock));
return (void *)0;
}
и код, который добавляет новый рабочий элемент в очередь:
void append(threadpool *pool, work_t *work)
{
work->next = NULL;
pthread_mutex_lock(&(pool->qlock));
if (pool->qtail) {
pool->qtail->next = work;
pool->qtail = work;
} else {
pool->qhead = work;
pool->qtail = work;
}
pthread_cond_signal(&(pool->q_not_empty));
pthread_mutex_unlock(&(pool->qlock));
}
Трудно сказать, где реализация OP утечка памяти. Наиболее вероятным кандидатом является член arg
OP в каждом work_t
, если он выделяется динамически.
Моя реализация выше передает всю work_t
функции routine
, которую я переименовал в process
. Он также отвечает за освобождение рабочей структуры. Минимальное определение для структуры работы:
typedef struct work_t {
struct work_t *next;
void (*process)(struct work_t *);
/* Optional other fields */
} work_t;
Другие возможные причины утечек памяти связаны с тем, что элемент qsize
не везде обновляется должным образом. Потому что на самом деле это бесполезно, я просто опускаю все это.
Чем проще код, тем легче избежать ошибок.