mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
9fd88560d5
Complete overhaul of the concurrency-related aspects of the library (threading, atomics, locking, etc.), adding private routines in the H5TS package to allow internal algorithms to use all of these capabilities. Adds many new features & components in the H5TS package that are equivalent to common concurrency data structures and capabilities: "regular" and recursive mutices, condition variables, semaphores, thread barriers, 'once' support, thread pools, atomic variables, thread-local keys, and spawning & joining internal threads. Now supports C11, pthreads, and Windows threading for all H5TS capabilities, except the recursive readers/writers lock, which is not supported on Windows (because Windows threads don't provide a callback on thread-local variable deletion). The "global" API lock is switched to use a recursive mutex from the H5TS package, instead of its own variant. API context code (H5CX package) and error stacks (H5E package) now use the common thread-local info, instead of their own variants. Subfiling code is switched from using Mercury threading features to the new internal H5TS features. Removes the mercury threading code. Adds a configure option (--enable-threads / HDF5_ENABLE_THREADS), enabled by default, to control whether threading is enabled within the library.
180 lines
5.7 KiB
C
180 lines
5.7 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/********************************************************************
|
|
*
|
|
* Test the correctness of the thread pool routines
|
|
*
|
|
********************************************************************/
|
|
|
|
#include "ttsafe.h"
|
|
|
|
#ifdef H5_HAVE_THREADS
|
|
|
|
#define NUM_THREADS 16
|
|
|
|
static H5TS_atomic_int_t counter_g;
|
|
|
|
static H5TS_THREAD_RETURN_TYPE
|
|
noop_task(void *_counter)
|
|
{
|
|
H5TS_atomic_int_t *counter = (H5TS_atomic_int_t *)_counter;
|
|
H5TS_thread_ret_t ret_value = 0;
|
|
|
|
VERIFY(H5TS_atomic_load_int(counter), 0, "noop_task");
|
|
|
|
return ret_value;
|
|
}
|
|
|
|
static H5TS_THREAD_RETURN_TYPE
|
|
incr_task(void *_counter)
|
|
{
|
|
H5TS_atomic_int_t *counter = (H5TS_atomic_int_t *)_counter;
|
|
H5TS_thread_ret_t ret_value = 0;
|
|
|
|
H5TS_atomic_fetch_add_int(counter, 1);
|
|
|
|
return ret_value;
|
|
}
|
|
|
|
static H5TS_THREAD_RETURN_TYPE
|
|
decr_task(void *_counter)
|
|
{
|
|
H5TS_atomic_int_t *counter = (H5TS_atomic_int_t *)_counter;
|
|
H5TS_thread_ret_t ret_value = 0;
|
|
|
|
H5TS_atomic_fetch_sub_int(counter, 1);
|
|
|
|
return ret_value;
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* tts_atomics
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
void
|
|
tts_atomics(void)
|
|
{
|
|
H5TS_pool_t *pool = NULL;
|
|
herr_t result;
|
|
|
|
/* Initialize the counter */
|
|
H5TS_atomic_init_int(&counter_g, 0);
|
|
|
|
/* Sanity checks on bad input */
|
|
result = H5TS_pool_create(NULL, NUM_THREADS);
|
|
VERIFY(result, FAIL, "H5TS_pool_create");
|
|
result = H5TS_pool_create(&pool, 0);
|
|
VERIFY(result, FAIL, "H5TS_pool_create");
|
|
result = H5TS_pool_add_task(NULL, noop_task, NULL);
|
|
VERIFY(result, FAIL, "H5TS_pool_add_task");
|
|
result = H5TS_pool_add_task(pool, NULL, NULL);
|
|
VERIFY(result, FAIL, "H5TS_pool_add_task");
|
|
result = H5TS_pool_destroy(NULL);
|
|
VERIFY(result, FAIL, "H5TS_pool_destroy");
|
|
|
|
/* Create & destroy empty pool */
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
/* Create pool, add single 'noop' task, destroy pool */
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
result = H5TS_pool_add_task(pool, noop_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
VERIFY(H5TS_atomic_load_int(&counter_g), 0, "noop");
|
|
|
|
/* Create pool, add single 'incr' task, destroy pool */
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
result = H5TS_pool_add_task(pool, incr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
VERIFY(H5TS_atomic_load_int(&counter_g), 1, "single incr");
|
|
|
|
/* Create pool, add pair of 'incr' & 'decr' tasks, destroy pool */
|
|
H5TS_atomic_store_int(&counter_g, 10);
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
result = H5TS_pool_add_task(pool, incr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
|
|
result = H5TS_pool_add_task(pool, decr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
VERIFY(H5TS_atomic_load_int(&counter_g), 10, "incr + decr");
|
|
|
|
/* Create pool, add many 'incr' & 'decr' tasks, destroy pool */
|
|
H5TS_atomic_store_int(&counter_g, 3);
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
for (unsigned u = 0; u < 200; u++) {
|
|
result = H5TS_pool_add_task(pool, incr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
}
|
|
|
|
for (unsigned u = 0; u < 100; u++) {
|
|
result = H5TS_pool_add_task(pool, decr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
}
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
VERIFY(H5TS_atomic_load_int(&counter_g), 103, "200 incr + 100 decr");
|
|
|
|
/* Create pool, add *lots* of 'incr' & 'decr' tasks, destroy pool */
|
|
H5TS_atomic_store_int(&counter_g, 5);
|
|
result = H5TS_pool_create(&pool, NUM_THREADS);
|
|
CHECK_I(result, "H5TS_pool_create");
|
|
|
|
for (unsigned u = 0; u < 2 * 1000 * 1000; u++) {
|
|
result = H5TS_pool_add_task(pool, incr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
}
|
|
|
|
for (unsigned u = 0; u < 1 * 1000 * 1000; u++) {
|
|
result = H5TS_pool_add_task(pool, decr_task, &counter_g);
|
|
CHECK_I(result, "H5TS_pool_add_task");
|
|
}
|
|
|
|
result = H5TS_pool_destroy(pool);
|
|
CHECK_I(result, "H5TS_pool_destroy");
|
|
|
|
VERIFY(H5TS_atomic_load_int(&counter_g), 5 + (1000 * 1000), "2,000,000 incr + 1,000,000 decr");
|
|
|
|
/* Destroy the atomic counter */
|
|
H5TS_atomic_destroy_int(&counter_g);
|
|
|
|
} /* end tts_atomics() */
|
|
|
|
#endif /* H5_HAVE_THREADS */
|