1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Source : test.c
8**
9** Purpose: Test for InterlockedCompareExchange() function using multiple threads
10**
11**
12**=========================================================*/
13
14
15
16#include <palsuite.h>
17
18#define MAX_THREADS 10
19#define REPEAT_COUNT 10
20
21//Global Variable Declaration
22LONG g_Total = 0;
23LONG Lock=0;
24
25
26void ModifyGlobalResource(void);
27void AcquireLock(PLONG pLock);
28void ReleaseLock(PLONG pLock);
29
30
31
32//Main entry point of the program
33int __cdecl main(int argc, char *argv[]) {
34
35 int i = 0;
36 DWORD dwThreadID=0;
37 LONG totalOperations = 0;
38
39 HANDLE hThread[MAX_THREADS];
40
41 /*
42 * Initialize the PAL and return FAILURE if this fails
43 */
44
45 if(0 != (PAL_Initialize(argc, argv)))
46 {
47 return FAIL;
48 }
49
50
51 totalOperations = MAX_THREADS * REPEAT_COUNT;
52
53
54 //Create MAX_THREADS threads that will operate on the global counter
55 for (i=0;i<MAX_THREADS;i++)
56 {
57 hThread[i] = CreateThread(
58 NULL, // default security attributes
59 0, // use default stack size
60 (LPTHREAD_START_ROUTINE) ModifyGlobalResource, // thread function
61 NULL, // argument to thread function
62 0, // use default creation flags
63 &dwThreadID); // returns the thread identifier
64
65 // Check the return value for success.
66
67 if (hThread[i] == NULL)
68 {
69 Fail("ERROR: Was not able to create thread\n"
70 "GetLastError returned %d\n", GetLastError());
71 }
72
73 }
74
75
76 //Wait for all threads to finish
77 for (i=0;i<MAX_THREADS;i++)
78 {
79
80 if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
81 {
82 Fail ("Main: Wait for Single Object failed. Failing test.\n"
83 "GetLastError returned %d\n", GetLastError());
84 }
85
86 }
87
88
89 if (0!= g_Total)
90 {
91 Fail("Test Failed \n");
92 }
93
94 Trace("Global Counter Value at the end of the test %d \n", g_Total);
95
96 /*
97 * Terminate PAL
98 */
99
100 PAL_Terminate();
101 return PASS;
102}
103
104
105void ModifyGlobalResource(void)
106{
107
108 int i =0;
109
110 for (i=0;i<REPEAT_COUNT;i++)
111 {
112
113 /*
114 Acquire Lock Provides Synchronization Around g_Total global variable
115 */
116
117 AcquireLock(&Lock);
118
119 /*
120 The following set of operations is guaranteed to be atomic by virtue of the fact
121 that InterLockedCompareExchange was able to guarantee that the compare
122 and exchange operation on pLock was thread safe. If the same set of code was
123 executed without using InterlockedCompareExchange the code would fail most of
124 time.
125
126 */
127 g_Total++;
128 Sleep(100);
129 g_Total--;
130 if (0!=g_Total)
131 {
132 Fail("Test Failed beacuse g_Total was not protected \n");
133 }
134
135
136 /*
137 Acquire Lock releases the lock around g_Total Global variable
138 */
139
140 ReleaseLock(&Lock);
141 }
142
143
144}
145
146
147void AcquireLock(PLONG pLock)
148{
149 //Spin Lock implemented with the help of InterlockedCompareExchange
150
151
152 while(1)
153 {
154 if (InterlockedCompareExchange(pLock,1,0)==0)
155 break;
156 }
157
158}
159
160
161void ReleaseLock(PLONG pLock)
162{
163
164
165 MemoryBarrier();
166 *pLock = 0;
167}
168
169