Line data Source code
1 : /****************************************************************************** 2 : * $Id$ 3 : * 4 : * Project: GDAL Core 5 : * Purpose: Test thread API 6 : * Author: Even Rouault, <even dot rouault at spatialys.com> 7 : * 8 : ****************************************************************************** 9 : * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com> 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #ifndef DEBUG 15 : #define DEBUG 16 : #endif 17 : 18 : #include "cpl_multiproc.h" 19 : #include "cpl_string.h" 20 : 21 : #include "gtest_include.h" 22 : 23 : namespace 24 : { 25 : 26 : // --------------------------------------------------------------------------- 27 : 28 : CPLCond *hCond = nullptr; 29 : CPLCond *hCondJobFinished = nullptr; 30 : CPLMutex *hClientMutex = nullptr; 31 : 32 : struct _JobItem 33 : { 34 : int nJobNumber; 35 : struct _JobItem *psNext; 36 : }; 37 : typedef struct _JobItem JobItem; 38 : 39 : JobItem *psJobList = nullptr; 40 : int nJobListSize = 0; 41 : int nThreadTotal = 0; 42 : int bProducedFinished = 0; 43 : int bVerbose = FALSE; 44 : 45 1 : static void ProducerThread(void * /* unused */) 46 : { 47 : int i; 48 1 : int jobNumber = 0; 49 : JobItem *psItem; 50 : 51 69906 : while (jobNumber < 1000) 52 : { 53 69905 : CPLAcquireMutex(hClientMutex, 1000.0); 54 : 55 70905 : for (i = 0; i < nThreadTotal; i++) 56 : { 57 1000 : jobNumber++; 58 1000 : nJobListSize++; 59 1000 : psItem = (JobItem *)malloc(sizeof(JobItem)); 60 1000 : psItem->nJobNumber = jobNumber; 61 1000 : psItem->psNext = psJobList; 62 1000 : psJobList = psItem; 63 : } 64 : 65 69905 : CPLCondBroadcast(hCond); 66 : 67 70087 : while (nJobListSize > nThreadTotal) 68 : { 69 182 : CPLCondWait(hCondJobFinished, hClientMutex); 70 : } 71 69905 : CPLReleaseMutex(hClientMutex); 72 : } 73 : 74 1 : CPLAcquireMutex(hClientMutex, 1000.0); 75 1 : bProducedFinished = 1; 76 1 : CPLCondBroadcast(hCond); 77 1 : CPLReleaseMutex(hClientMutex); 78 1 : } 79 : 80 10 : static void ConsumerThread(void *pIndex) 81 : { 82 : int nJobNumber; 83 : int nThreadIndex; 84 : JobItem *psNext; 85 : 86 10 : nThreadIndex = *(int *)pIndex; 87 10 : free(pIndex); 88 : 89 10 : if (bVerbose) 90 0 : printf("Thread %d created\n", nThreadIndex); 91 : 92 10 : nThreadTotal++; 93 : 94 : while (TRUE) 95 : { 96 1009 : CPLAcquireMutex(hClientMutex, 1000.0); 97 1147 : while (psJobList == nullptr && !bProducedFinished) 98 137 : CPLCondWait(hCond, hClientMutex); 99 1010 : if (bProducedFinished) 100 : { 101 10 : CPLReleaseMutex(hClientMutex); 102 10 : break; 103 : } 104 : 105 1000 : nJobNumber = psJobList->nJobNumber; 106 1000 : psNext = psJobList->psNext; 107 1000 : free(psJobList); 108 1000 : psJobList = psNext; 109 1000 : CPLReleaseMutex(hClientMutex); 110 : 111 999 : if (bVerbose) 112 0 : printf("Thread %d consumed job %d\n", nThreadIndex, nJobNumber); 113 : 114 999 : CPLAcquireMutex(hClientMutex, 1000.0); 115 1000 : nJobListSize--; 116 1000 : CPLCondSignal(hCondJobFinished); 117 1000 : CPLReleaseMutex(hClientMutex); 118 : } 119 10 : } 120 : 121 4 : TEST(testthreadcond, test) 122 : { 123 : int i; 124 : CPLJoinableThread *apThreads[10]; 125 : 126 1 : bVerbose = CPLTestBool(CPLGetConfigOption("VERBOSE", "NO")); 127 : 128 1 : hCond = CPLCreateCond(); 129 1 : hCondJobFinished = CPLCreateCond(); 130 : 131 1 : hClientMutex = CPLCreateMutex(); 132 1 : CPLReleaseMutex(hClientMutex); 133 : 134 1 : CPLCreateThread(ProducerThread, nullptr); 135 : 136 11 : for (i = 0; i < 10; i++) 137 : { 138 10 : int *pi = (int *)malloc(sizeof(int)); 139 10 : *pi = i; 140 10 : apThreads[i] = CPLCreateJoinableThread(ConsumerThread, pi); 141 : } 142 : 143 11 : for (i = 0; i < 10; i++) 144 : { 145 10 : CPLJoinThread(apThreads[i]); 146 : } 147 : 148 1 : CPLDestroyCond(hCond); 149 1 : CPLDestroyCond(hCondJobFinished); 150 1 : CPLDestroyMutex(hClientMutex); 151 1 : } 152 : 153 : } // namespace