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