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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #ifndef DEBUG
31 : #define DEBUG
32 : #endif
33 :
34 : #include "cpl_multiproc.h"
35 : #include "cpl_string.h"
36 :
37 : #include "gtest_include.h"
38 :
39 : namespace
40 : {
41 :
42 : // ---------------------------------------------------------------------------
43 :
44 : CPLCond *hCond = nullptr;
45 : CPLCond *hCondJobFinished = nullptr;
46 : CPLMutex *hClientMutex = nullptr;
47 :
48 : struct _JobItem
49 : {
50 : int nJobNumber;
51 : struct _JobItem *psNext;
52 : };
53 : typedef struct _JobItem JobItem;
54 :
55 : JobItem *psJobList = nullptr;
56 : int nJobListSize = 0;
57 : int nThreadTotal = 0;
58 : int bProducedFinished = 0;
59 : int bVerbose = FALSE;
60 :
61 1 : static void ProducerThread(void * /* unused */)
62 : {
63 : int i;
64 1 : int jobNumber = 0;
65 : JobItem *psItem;
66 :
67 109 : while (jobNumber < 1000)
68 : {
69 108 : CPLAcquireMutex(hClientMutex, 1000.0);
70 :
71 1110 : for (i = 0; i < nThreadTotal; i++)
72 : {
73 1002 : jobNumber++;
74 1002 : nJobListSize++;
75 1002 : psItem = (JobItem *)malloc(sizeof(JobItem));
76 1002 : psItem->nJobNumber = jobNumber;
77 1002 : psItem->psNext = psJobList;
78 1002 : psJobList = psItem;
79 : }
80 :
81 108 : CPLCondBroadcast(hCond);
82 :
83 197 : while (nJobListSize > nThreadTotal)
84 : {
85 89 : CPLCondWait(hCondJobFinished, hClientMutex);
86 : }
87 108 : CPLReleaseMutex(hClientMutex);
88 : }
89 :
90 1 : CPLAcquireMutex(hClientMutex, 1000.0);
91 1 : bProducedFinished = 1;
92 1 : CPLCondBroadcast(hCond);
93 1 : CPLReleaseMutex(hClientMutex);
94 1 : }
95 :
96 10 : static void ConsumerThread(void *pIndex)
97 : {
98 : int nJobNumber;
99 : int nThreadIndex;
100 : JobItem *psNext;
101 :
102 10 : nThreadIndex = *(int *)pIndex;
103 10 : free(pIndex);
104 :
105 10 : if (bVerbose)
106 0 : printf("Thread %d created\n", nThreadIndex);
107 :
108 10 : nThreadTotal++;
109 :
110 : while (TRUE)
111 : {
112 1000 : CPLAcquireMutex(hClientMutex, 1000.0);
113 1432 : while (psJobList == nullptr && !bProducedFinished)
114 428 : CPLCondWait(hCond, hClientMutex);
115 1004 : if (bProducedFinished)
116 : {
117 10 : CPLReleaseMutex(hClientMutex);
118 10 : break;
119 : }
120 :
121 994 : nJobNumber = psJobList->nJobNumber;
122 994 : psNext = psJobList->psNext;
123 994 : free(psJobList);
124 994 : psJobList = psNext;
125 994 : CPLReleaseMutex(hClientMutex);
126 :
127 989 : if (bVerbose)
128 0 : printf("Thread %d consumed job %d\n", nThreadIndex, nJobNumber);
129 :
130 989 : CPLAcquireMutex(hClientMutex, 1000.0);
131 994 : nJobListSize--;
132 994 : CPLCondSignal(hCondJobFinished);
133 994 : CPLReleaseMutex(hClientMutex);
134 : }
135 10 : }
136 :
137 4 : TEST(testthreadcond, test)
138 : {
139 : int i;
140 : CPLJoinableThread *apThreads[10];
141 :
142 1 : bVerbose = CPLTestBool(CPLGetConfigOption("VERBOSE", "NO"));
143 :
144 1 : hCond = CPLCreateCond();
145 1 : hCondJobFinished = CPLCreateCond();
146 :
147 1 : hClientMutex = CPLCreateMutex();
148 1 : CPLReleaseMutex(hClientMutex);
149 :
150 1 : CPLCreateThread(ProducerThread, nullptr);
151 :
152 11 : for (i = 0; i < 10; i++)
153 : {
154 10 : int *pi = (int *)malloc(sizeof(int));
155 10 : *pi = i;
156 10 : apThreads[i] = CPLCreateJoinableThread(ConsumerThread, pi);
157 : }
158 :
159 11 : for (i = 0; i < 10; i++)
160 : {
161 10 : CPLJoinThread(apThreads[i]);
162 : }
163 :
164 1 : CPLDestroyCond(hCond);
165 1 : CPLDestroyCond(hCondJobFinished);
166 1 : CPLDestroyMutex(hClientMutex);
167 1 : }
168 :
169 : } // namespace
|