6 ex__thread__pool__discard_8c
gullradriel edited this page 2026-10-09 00:55:18 +02:00

examples/ex_thread_pool_discard.c

destroy_threaded_pool() does not drop queued jobs silently. More...

Functions

Name
void * slow_job(void * p)
A job that takes 300 ms and releases its own param.
int run(unsigned int delay)
Queue four slow jobs on a one thread pool and destroy it.
int main(void )
void discard_job(void * p)
Discard function: releases a param that will never be run.

Attributes

Name
int ran
Jobs that ran, and params the discard function released.
int discarded
pthread_mutex_t count_lock
Guards the two counters.

Detailed Description

destroy_threaded_pool() does not drop queued jobs silently.

Author: Castagnier Mickael

Version: 1.0

Date: 22/09/2026

One thread, one slow job running and three queued behind it. With a retry budget shorter than the running job, destroy gives up waiting, joins the thread - which still waits for the running job - and discards the three queued ones without running them. Their params used to go with them, unreleased and unmentioned; under a leak checker that was three leaks and nowhere else was it visible.

Now each discarded param is handed to the pool's discard function. This checks that exactly the three queued jobs are discarded, that the running one completes, and that a budget long enough to drain the queue runs all four and discards none. Run under ASan, a param that nobody releases fails the run.

Functions Documentation

function slow_job

static void * slow_job(
    void * p
)

A job that takes 300 ms and releases its own param.

Parameters:

  • p A malloc'd int.

Return: NULL

function run

static int run(
    unsigned int delay
)

Queue four slow jobs on a one thread pool and destroy it.

Parameters:

Return: 0 when every job was set up, 1 otherwise.

function main

int main(
    void 
)

function discard_job

static void discard_job(
    void * p
)

Discard function: releases a param that will never be run.

Parameters:

  • p A malloc'd int.

Attributes Documentation

variable ran

static int ran = 0;

Jobs that ran, and params the discard function released.

variable discarded

static int discarded = 0;

variable count_lock

static pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;

Guards the two counters.

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "nilorea/n_common.h"
#include "nilorea/n_log.h"
#include "nilorea/n_thread_pool.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static int ran = 0, discarded = 0;
static pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;

static void* slow_job(void* p) {
    usleep(300000);
    pthread_mutex_lock(&count_lock);
    ran++;
    pthread_mutex_unlock(&count_lock);
    free(p);
    return NULL;
}

static void discard_job(void* p) {
    pthread_mutex_lock(&count_lock);
    discarded++;
    pthread_mutex_unlock(&count_lock);
    free(p);
}

static int run(unsigned int delay) {
    THREAD_POOL* pool = new_thread_pool(1, 0);
    int i = 0;

    if (!pool) return 1;
    set_thread_pool_discard(pool, discard_job);
    ran = discarded = 0;
    for (i = 0; i < 4; i++) {
        int* p = malloc(sizeof(int));
        if (!p) return 1;
        *p = i;
        if (add_threaded_process(pool, slow_job, p, NORMAL_PROC) != TRUE) {
            free(p);
            return 1;
        }
    }
    usleep(20000); /* let the first one start */
    destroy_threaded_pool(&pool, delay);
    return 0;
}

int main(void) {
    int failures = 0;

    /* The error line destroy logs for the short budget is the expected
       outcome here, so it is not shown. */
    set_log_level(LOG_NULL);

    /* 1000 retries of 100 us is 0.1 s, shorter than the running job. */
    if (run(100) != 0) failures++;
    if (ran != 1 || discarded != 3) {
        fprintf(stderr, "short budget: %d ran and %d discarded, wanted 1 and 3\n", ran, discarded);
        failures++;
    }
    /* 1000 retries of 1 ms is a second: the queue drains inside it. */
    if (run(1000) != 0) failures++;
    if (ran != 4 || discarded != 0) {
        fprintf(stderr, "long budget: %d ran and %d discarded, wanted 4 and 0\n", ran, discarded);
        failures++;
    }
    if (failures) {
        fprintf(stderr, "ex_thread_pool_discard: %d failure(s)\n", failures);
        return 1;
    }
    printf("ex_thread_pool_discard: all checks passed\n");
    return 0;
}