Modern Multithreading: Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 [First Edition] 0471725048, 9780471725046

Modern Multithreading is a textbook and professional reference on concurrent programming. The book describes fundamental

272 95 2MB

English Pages 481 Year 2005

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
cover.pdf......Page 1
page_c2.pdf......Page 2
page_r01.pdf......Page 3
page_r02.pdf......Page 4
page_r03.pdf......Page 5
page_r04.pdf......Page 6
page_r05.pdf......Page 7
page_r06.pdf......Page 8
page_r07.pdf......Page 9
page_r08.pdf......Page 10
page_r09.pdf......Page 11
page_r10.pdf......Page 12
page_r11.pdf......Page 13
page_r12.pdf......Page 14
page_r13.pdf......Page 15
page_r14.pdf......Page 16
page_z0001.pdf......Page 17
page_z0002.pdf......Page 18
page_z0003.pdf......Page 19
page_z0004.pdf......Page 20
page_z0005.pdf......Page 21
page_z0006.pdf......Page 22
page_z0007.pdf......Page 23
page_z0008.pdf......Page 24
page_z0009.pdf......Page 25
page_z0010.pdf......Page 26
page_z0011.pdf......Page 27
page_z0012.pdf......Page 28
page_z0013.pdf......Page 29
page_z0014.pdf......Page 30
page_z0015.pdf......Page 31
page_z0016.pdf......Page 32
page_z0017.pdf......Page 33
page_z0018.pdf......Page 34
page_z0019.pdf......Page 35
page_z0020.pdf......Page 36
page_z0021.pdf......Page 37
page_z0022.pdf......Page 38
page_z0023.pdf......Page 39
page_z0024.pdf......Page 40
page_z0025.pdf......Page 41
page_z0026.pdf......Page 42
page_z0027.pdf......Page 43
page_z0028.pdf......Page 44
page_z0029.pdf......Page 45
page_z0030.pdf......Page 46
page_z0031.pdf......Page 47
page_z0032.pdf......Page 48
page_z0033.pdf......Page 49
page_z0034.pdf......Page 50
page_z0035.pdf......Page 51
page_z0036.pdf......Page 52
page_z0037.pdf......Page 53
page_z0038.pdf......Page 54
page_z0039.pdf......Page 55
page_z0040.pdf......Page 56
page_z0041.pdf......Page 57
page_z0042.pdf......Page 58
page_z0043.pdf......Page 59
page_z0044.pdf......Page 60
page_z0045.pdf......Page 61
page_z0046.pdf......Page 62
page_z0047.pdf......Page 63
page_z0048.pdf......Page 64
page_z0049.pdf......Page 65
page_z0050.pdf......Page 66
page_z0051.pdf......Page 67
page_z0052.pdf......Page 68
page_z0053.pdf......Page 69
page_z0054.pdf......Page 70
page_z0055.pdf......Page 71
page_z0056.pdf......Page 72
page_z0057.pdf......Page 73
page_z0058.pdf......Page 74
page_z0059.pdf......Page 75
page_z0060.pdf......Page 76
page_z0061.pdf......Page 77
page_z0062.pdf......Page 78
page_z0063.pdf......Page 79
page_z0064.pdf......Page 80
page_z0065.pdf......Page 81
page_z0066.pdf......Page 82
page_z0067.pdf......Page 83
page_z0068.pdf......Page 84
page_z0069.pdf......Page 85
page_z0070.pdf......Page 86
page_z0071.pdf......Page 87
page_z0072.pdf......Page 88
page_z0073.pdf......Page 89
page_z0074.pdf......Page 90
page_z0075.pdf......Page 91
page_z0076.pdf......Page 92
page_z0077.pdf......Page 93
page_z0078.pdf......Page 94
page_z0079.pdf......Page 95
page_z0080.pdf......Page 96
page_z0081.pdf......Page 97
page_z0082.pdf......Page 98
page_z0083.pdf......Page 99
page_z0084.pdf......Page 100
page_z0085.pdf......Page 101
page_z0086.pdf......Page 102
page_z0087.pdf......Page 103
page_z0088.pdf......Page 104
page_z0089.pdf......Page 105
page_z0090.pdf......Page 106
page_z0091.pdf......Page 107
page_z0092.pdf......Page 108
page_z0093.pdf......Page 109
page_z0094.pdf......Page 110
page_z0095.pdf......Page 111
page_z0096.pdf......Page 112
page_z0097.pdf......Page 113
page_z0098.pdf......Page 114
page_z0099.pdf......Page 115
page_z0100.pdf......Page 116
page_z0101.pdf......Page 117
page_z0102.pdf......Page 118
page_z0103.pdf......Page 119
page_z0104.pdf......Page 120
page_z0105.pdf......Page 121
page_z0106.pdf......Page 122
page_z0107.pdf......Page 123
page_z0108.pdf......Page 124
page_z0109.pdf......Page 125
page_z0110.pdf......Page 126
page_z0111.pdf......Page 127
page_z0112.pdf......Page 128
page_z0113.pdf......Page 129
page_z0114.pdf......Page 130
page_z0115.pdf......Page 131
page_z0116.pdf......Page 132
page_z0117.pdf......Page 133
page_z0118.pdf......Page 134
page_z0119.pdf......Page 135
page_z0120.pdf......Page 136
page_z0121.pdf......Page 137
page_z0122.pdf......Page 138
page_z0123.pdf......Page 139
page_z0124.pdf......Page 140
page_z0125.pdf......Page 141
page_z0126.pdf......Page 142
page_z0127.pdf......Page 143
page_z0128.pdf......Page 144
page_z0129.pdf......Page 145
page_z0130.pdf......Page 146
page_z0131.pdf......Page 147
page_z0132.pdf......Page 148
page_z0133.pdf......Page 149
page_z0134.pdf......Page 150
page_z0135.pdf......Page 151
page_z0136.pdf......Page 152
page_z0137.pdf......Page 153
page_z0138.pdf......Page 154
page_z0139.pdf......Page 155
page_z0140.pdf......Page 156
page_z0141.pdf......Page 157
page_z0142.pdf......Page 158
page_z0143.pdf......Page 159
page_z0144.pdf......Page 160
page_z0145.pdf......Page 161
page_z0146.pdf......Page 162
page_z0147.pdf......Page 163
page_z0148.pdf......Page 164
page_z0149.pdf......Page 165
page_z0150.pdf......Page 166
page_z0151.pdf......Page 167
page_z0152.pdf......Page 168
page_z0153.pdf......Page 169
page_z0154.pdf......Page 170
page_z0155.pdf......Page 171
page_z0156.pdf......Page 172
page_z0157.pdf......Page 173
page_z0158.pdf......Page 174
page_z0159.pdf......Page 175
page_z0160.pdf......Page 176
page_z0161.pdf......Page 177
page_z0162.pdf......Page 178
page_z0163.pdf......Page 179
page_z0164.pdf......Page 180
page_z0165.pdf......Page 181
page_z0166.pdf......Page 182
page_z0167.pdf......Page 183
page_z0168.pdf......Page 184
page_z0169.pdf......Page 185
page_z0170.pdf......Page 186
page_z0171.pdf......Page 187
page_z0172.pdf......Page 188
page_z0173.pdf......Page 189
page_z0174.pdf......Page 190
page_z0175.pdf......Page 191
page_z0176.pdf......Page 192
page_z0177.pdf......Page 193
page_z0178.pdf......Page 194
page_z0179.pdf......Page 195
page_z0180.pdf......Page 196
page_z0181.pdf......Page 197
page_z0182.pdf......Page 198
page_z0183.pdf......Page 199
page_z0184.pdf......Page 200
page_z0185.pdf......Page 201
page_z0186.pdf......Page 202
page_z0187.pdf......Page 203
page_z0188.pdf......Page 204
page_z0189.pdf......Page 205
page_z0190.pdf......Page 206
page_z0191.pdf......Page 207
page_z0192.pdf......Page 208
page_z0193.pdf......Page 209
page_z0194.pdf......Page 210
page_z0195.pdf......Page 211
page_z0196.pdf......Page 212
page_z0197.pdf......Page 213
page_z0198.pdf......Page 214
page_z0199.pdf......Page 215
page_z0200.pdf......Page 216
page_z0201.pdf......Page 217
page_z0202.pdf......Page 218
page_z0203.pdf......Page 219
page_z0204.pdf......Page 220
page_z0205.pdf......Page 221
page_z0206.pdf......Page 222
page_z0207.pdf......Page 223
page_z0208.pdf......Page 224
page_z0209.pdf......Page 225
page_z0210.pdf......Page 226
page_z0211.pdf......Page 227
page_z0212.pdf......Page 228
page_z0213.pdf......Page 229
page_z0214.pdf......Page 230
page_z0215.pdf......Page 231
page_z0216.pdf......Page 232
page_z0217.pdf......Page 233
page_z0218.pdf......Page 234
page_z0219.pdf......Page 235
page_z0220.pdf......Page 236
page_z0221.pdf......Page 237
page_z0222.pdf......Page 238
page_z0223.pdf......Page 239
page_z0224.pdf......Page 240
page_z0225.pdf......Page 241
page_z0226.pdf......Page 242
page_z0227.pdf......Page 243
page_z0228.pdf......Page 244
page_z0229.pdf......Page 245
page_z0230.pdf......Page 246
page_z0231.pdf......Page 247
page_z0232.pdf......Page 248
page_z0233.pdf......Page 249
page_z0234.pdf......Page 250
page_z0235.pdf......Page 251
page_z0236.pdf......Page 252
page_z0237.pdf......Page 253
page_z0238.pdf......Page 254
page_z0239.pdf......Page 255
page_z0240.pdf......Page 256
page_z0241.pdf......Page 257
page_z0242.pdf......Page 258
page_z0243.pdf......Page 259
page_z0244.pdf......Page 260
page_z0245.pdf......Page 261
page_z0246.pdf......Page 262
page_z0247.pdf......Page 263
page_z0248.pdf......Page 264
page_z0249.pdf......Page 265
page_z0250.pdf......Page 266
page_z0251.pdf......Page 267
page_z0252.pdf......Page 268
page_z0253.pdf......Page 269
page_z0254.pdf......Page 270
page_z0255.pdf......Page 271
page_z0256.pdf......Page 272
page_z0257.pdf......Page 273
page_z0258.pdf......Page 274
page_z0259.pdf......Page 275
page_z0260.pdf......Page 276
page_z0261.pdf......Page 277
page_z0262.pdf......Page 278
page_z0263.pdf......Page 279
page_z0264.pdf......Page 280
page_z0265.pdf......Page 281
page_z0266.pdf......Page 282
page_z0267.pdf......Page 283
page_z0268.pdf......Page 284
page_z0269.pdf......Page 285
page_z0270.pdf......Page 286
page_z0271.pdf......Page 287
page_z0272.pdf......Page 288
page_z0273.pdf......Page 289
page_z0274.pdf......Page 290
page_z0275.pdf......Page 291
page_z0276.pdf......Page 292
page_z0277.pdf......Page 293
page_z0278.pdf......Page 294
page_z0279.pdf......Page 295
page_z0280.pdf......Page 296
page_z0281.pdf......Page 297
page_z0282.pdf......Page 298
page_z0283.pdf......Page 299
page_z0284.pdf......Page 300
page_z0285.pdf......Page 301
page_z0286.pdf......Page 302
page_z0287.pdf......Page 303
page_z0288.pdf......Page 304
page_z0289.pdf......Page 305
page_z0290.pdf......Page 306
page_z0291.pdf......Page 307
page_z0292.pdf......Page 308
page_z0293.pdf......Page 309
page_z0294.pdf......Page 310
page_z0295.pdf......Page 311
page_z0296.pdf......Page 312
page_z0297.pdf......Page 313
page_z0298.pdf......Page 314
page_z0299.pdf......Page 315
page_z0300.pdf......Page 316
page_z0301.pdf......Page 317
page_z0302.pdf......Page 318
page_z0303.pdf......Page 319
page_z0304.pdf......Page 320
page_z0305.pdf......Page 321
page_z0306.pdf......Page 322
page_z0307.pdf......Page 323
page_z0308.pdf......Page 324
page_z0309.pdf......Page 325
page_z0310.pdf......Page 326
page_z0311.pdf......Page 327
page_z0312.pdf......Page 328
page_z0313.pdf......Page 329
page_z0314.pdf......Page 330
page_z0315.pdf......Page 331
page_z0316.pdf......Page 332
page_z0317.pdf......Page 333
page_z0318.pdf......Page 334
page_z0319.pdf......Page 335
page_z0320.pdf......Page 336
page_z0321.pdf......Page 337
page_z0322.pdf......Page 338
page_z0323.pdf......Page 339
page_z0324.pdf......Page 340
page_z0325.pdf......Page 341
page_z0326.pdf......Page 342
page_z0327.pdf......Page 343
page_z0328.pdf......Page 344
page_z0329.pdf......Page 345
page_z0330.pdf......Page 346
page_z0331.pdf......Page 347
page_z0332.pdf......Page 348
page_z0333.pdf......Page 349
page_z0334.pdf......Page 350
page_z0335.pdf......Page 351
page_z0336.pdf......Page 352
page_z0337.pdf......Page 353
page_z0338.pdf......Page 354
page_z0339.pdf......Page 355
page_z0340.pdf......Page 356
page_z0341.pdf......Page 357
page_z0342.pdf......Page 358
page_z0343.pdf......Page 359
page_z0344.pdf......Page 360
page_z0345.pdf......Page 361
page_z0346.pdf......Page 362
page_z0347.pdf......Page 363
page_z0348.pdf......Page 364
page_z0349.pdf......Page 365
page_z0350.pdf......Page 366
page_z0351.pdf......Page 367
page_z0352.pdf......Page 368
page_z0353.pdf......Page 369
page_z0354.pdf......Page 370
page_z0355.pdf......Page 371
page_z0356.pdf......Page 372
page_z0357.pdf......Page 373
page_z0358.pdf......Page 374
page_z0359.pdf......Page 375
page_z0360.pdf......Page 376
page_z0361.pdf......Page 377
page_z0362.pdf......Page 378
page_z0363.pdf......Page 379
page_z0364.pdf......Page 380
page_z0365.pdf......Page 381
page_z0366.pdf......Page 382
page_z0367.pdf......Page 383
page_z0368.pdf......Page 384
page_z0369.pdf......Page 385
page_z0370.pdf......Page 386
page_z0371.pdf......Page 387
page_z0372.pdf......Page 388
page_z0373.pdf......Page 389
page_z0374.pdf......Page 390
page_z0375.pdf......Page 391
page_z0376.pdf......Page 392
page_z0377.pdf......Page 393
page_z0378.pdf......Page 394
page_z0379.pdf......Page 395
page_z0380.pdf......Page 396
page_z0381.pdf......Page 397
page_z0382.pdf......Page 398
page_z0383.pdf......Page 399
page_z0384.pdf......Page 400
page_z0385.pdf......Page 401
page_z0386.pdf......Page 402
page_z0387.pdf......Page 403
page_z0388.pdf......Page 404
page_z0389.pdf......Page 405
page_z0390.pdf......Page 406
page_z0391.pdf......Page 407
page_z0392.pdf......Page 408
page_z0393.pdf......Page 409
page_z0394.pdf......Page 410
page_z0395.pdf......Page 411
page_z0396.pdf......Page 412
page_z0397.pdf......Page 413
page_z0398.pdf......Page 414
page_z0399.pdf......Page 415
page_z0400.pdf......Page 416
page_z0401.pdf......Page 417
page_z0402.pdf......Page 418
page_z0403.pdf......Page 419
page_z0404.pdf......Page 420
page_z0405.pdf......Page 421
page_z0406.pdf......Page 422
page_z0407.pdf......Page 423
page_z0408.pdf......Page 424
page_z0409.pdf......Page 425
page_z0410.pdf......Page 426
page_z0411.pdf......Page 427
page_z0412.pdf......Page 428
page_z0413.pdf......Page 429
page_z0414.pdf......Page 430
page_z0415.pdf......Page 431
page_z0416.pdf......Page 432
page_z0417.pdf......Page 433
page_z0418.pdf......Page 434
page_z0419.pdf......Page 435
page_z0420.pdf......Page 436
page_z0421.pdf......Page 437
page_z0422.pdf......Page 438
page_z0423.pdf......Page 439
page_z0424.pdf......Page 440
page_z0425.pdf......Page 441
page_z0426.pdf......Page 442
page_z0427.pdf......Page 443
page_z0428.pdf......Page 444
page_z0429.pdf......Page 445
page_z0430.pdf......Page 446
page_z0431.pdf......Page 447
page_z0432.pdf......Page 448
page_z0433.pdf......Page 449
page_z0434.pdf......Page 450
page_z0435.pdf......Page 451
page_z0436.pdf......Page 452
page_z0437.pdf......Page 453
page_z0438.pdf......Page 454
page_z0439.pdf......Page 455
page_z0440.pdf......Page 456
page_z0441.pdf......Page 457
page_z0442.pdf......Page 458
page_z0443.pdf......Page 459
page_z0444.pdf......Page 460
page_z0445.pdf......Page 461
page_z0446.pdf......Page 462
page_z0447.pdf......Page 463
page_z0448.pdf......Page 464
page_z0449.pdf......Page 465
page_z0450.pdf......Page 466
page_z0451.pdf......Page 467
page_z0452.pdf......Page 468
page_z0453.pdf......Page 469
page_z0454.pdf......Page 470
page_z0455.pdf......Page 471
page_z0456.pdf......Page 472
page_z0457.pdf......Page 473
page_z0458.pdf......Page 474
page_z0459.pdf......Page 475
page_z0460.pdf......Page 476
page_z0461.pdf......Page 477
page_z0462.pdf......Page 478
page_z0463.pdf......Page 479
page_z0464.pdf......Page 480
page_z0465.pdf......Page 481
Recommend Papers

Modern Multithreading: Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 [First Edition]
 0471725048, 9780471725046

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

MODERN MULTITHREADING Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs

RICHARD H. CARVER KUO-CHUNG TAI

A JOHN WILEY & SONS, INC., PUBLICATION

MODERN MULTITHREADING

MODERN MULTITHREADING Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs

RICHARD H. CARVER KUO-CHUNG TAI

A JOHN WILEY & SONS, INC., PUBLICATION

Copyright  2006 by John Wiley & Sons, Inc. All rights reserved. Published by John Wiley & Sons, Inc., Hoboken, New Jersey. Published simultaneously in Canada. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning, or otherwise, except as permitted under Section 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, Inc., 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 750-4470, or on the web at www.copyright.com. Requests to the Publisher for permission should be addressed to the Permissions Department, John Wiley & Sons, Inc., 111 River Street, Hoboken, NJ 07030, (201) 748-6011, fax (201) 748-6008, or online at http://www.wiley.com/go/permission. Limit of Liability/Disclaimer of Warranty: While the publisher and author have used their best efforts in preparing this book, they make no representations or warranties with respect to the accuracy or completeness of the contents of this book and specifically disclaim any implied warranties of merchantability or fitness for a particular purpose. No warranty may be created or extended by sales representatives or written sales materials. The advice and strategies contained herein may not be suitable for your situation. You should consult with a professional where appropriate. Neither the publisher nor author shall be liable for any loss of profit or any other commercial damages, including but not limited to special, incidental, consequential, or other damages. For general information on our other products and services or for technical support, please contact our Customer Care Department within the United States at (800) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic formats. For more information about Wiley products, visit our web site at www.wiley.com. Library of Congress Cataloging-in-Publication Data: Carver, Richard H., 1960– Modern multithreading: implementing, testing, and debugging multithreaded Java and C++/Pthreads/Win32 programs / by Richard H. Carver and Kuo-Chung Tai. p. cm. Includes bibliographical references and index. ISBN-13 978-0-471-72504-6 (paper) ISBN-10 0-471-72504-8 (paper) 1. Parallel programming (Computer science) 2. Threads (Computer programs) I. Tai, Kuo-Chung. II. Title. QA76.642.C38 2006 005.1′ 1–dc22 2005045775 Printed in the United States of America. 10 9 8 7 6 5 4 3 2 1

CONTENTS

Preface

xi

1 Introduction to Concurrent Programming

1

1.1 1.2 1.3 1.4 1.5 1.6

Processes and Threads: An Operating System’s View, 1 Advantages of Multithreading, 3 Threads in Java, 4 Threads in Win32, 6 Pthreads, 9 C++ Thread Class, 14 1.6.1 C++ Class Thread for Win32, 14 1.6.2 C++ Class Thread for Pthreads, 19 1.7 Thread Communication, 19 1.7.1 Nondeterministic Execution Behavior, 23 1.7.2 Atomic Actions, 25 1.8 Testing and Debugging Multithreaded Programs, 29 1.8.1 Problems and Issues, 30 1.8.2 Class TDThread for Testing and Debugging, 34 1.8.3 Tracing and Replaying Executions with Class Template sharedVariable, 37 1.9 Thread Synchronization, 38 Further Reading, 38 References, 39 Exercises, 41

v

vi

CONTENTS

2 The Critical Section Problem

46

2.1 Software Solutions to the Two-Thread Critical Section Problem, 47 2.1.1 Incorrect Solution 1, 48 2.1.2 Incorrect Solution 2, 49 2.1.3 Incorrect Solution 3, 50 2.1.4 Peterson’s Algorithm, 52 2.1.5 Using the volatile Modifier, 53 2.2 Ticket-Based Solutions to the n-Thread Critical Section Problem, 54 2.2.1 Ticket Algorithm, 54 2.2.2 Bakery Algorithm, 56 2.3 Hardware Solutions to the n-Thread Critical Section Problem, 58 2.3.1 Partial Solution, 59 2.3.2 Complete Solution, 59 2.3.3 Note on Busy-Waiting, 60 2.4 Deadlock, Livelock, and Starvation, 62 2.4.1 Deadlock, 62 2.4.2 Livelock, 62 2.4.3 Starvation, 63 2.5 Tracing and Replay for Shared Variables, 64 2.5.1 ReadWrite-Sequences, 65 2.5.2 Alternative Definition of ReadWrite-Sequences, 67 2.5.3 Tracing and Replaying ReadWrite-Sequences, 68 2.5.4 Class Template sharedVariable, 70 2.5.5 Putting It All Together, 71 2.5.6 Note on Shared Memory Consistency, 74 Further Reading, 77 References, 78 Exercises, 79 3 Semaphores and Locks 3.1 Counting Semaphores, 84 3.2 Using Semaphores, 86 3.2.1 Resource Allocation, 86 3.2.2 More Semaphore Patterns, 87 3.3 Binary Semaphores and Locks, 90 3.4 Implementing Semaphores, 92 3.4.1 Implementing P() and V(), 92 3.4.2 VP() Operation, 94 3.5 Semaphore-Based Solutions to Concurrent Programming Problems, 96 3.5.1 Event Ordering, 96

84

CONTENTS

vii

3.5.2 Bounded Buffer, 96 3.5.3 Dining Philosophers, 98 3.5.4 Readers and Writers, 101 3.5.5 Simulating Counting Semaphores, 108 3.6 Semaphores and Locks in Java, 111 3.6.1 Class countingSemaphore, 111 3.6.2 Class mutexLock, 113 3.6.3 Class Semaphore, 115 3.6.4 Class ReentrantLock, 116 3.6.5 Example: Java Bounded Buffer, 116 3.7 Semaphores and Locks in Win32, 119 3.7.1 CRITICAL SECTION, 119 3.7.2 Mutex, 122 3.7.3 Semaphore, 124 3.7.4 Events, 132 3.7.5 Other Synchronization Functions, 134 3.7.6 Example: C++/Win32 Bounded Buffer, 134 3.8 Semaphores and Locks in Pthreads, 134 3.8.1 Mutex, 136 3.8.2 Semaphore, 137 3.9 Another Note on Shared Memory Consistency, 141 3.10 Tracing, Testing, and Replay for Semaphores and Locks, 143 3.10.1 Nondeterministic Testing with the Lockset Algorithm, 143 3.10.2 Simple SYN-Sequences for Semaphores and Locks, 146 3.10.3 Tracing and Replaying Simple PV-Sequences and LockUnlock-Sequences, 150 3.10.4 Deadlock Detection, 154 3.10.5 Reachability Testing for Semaphores and Locks, 157 3.10.6 Putting It All Together, 160 Further Reading, 163 References, 164 Exercises, 166 4 Monitors 4.1 Definition of Monitors, 178 4.1.1 Mutual Exclusion, 178 4.1.2 Condition Variables and SC Signaling, 178 4.2 Monitor-Based Solutions to Concurrent Programming Problems, 182 4.2.1 Simulating Counting Semaphores, 182 4.2.2 Simulating Binary Semaphores, 183 4.2.3 Dining Philosophers, 183 4.2.4 Readers and Writers, 187

177

viii

CONTENTS

4.3 Monitors in Java, 187 4.3.1 Better countingSemaphore, 190 4.3.2 notify vs. notifyAll, 191 4.3.3 Simulating Multiple Condition Variables, 194 4.4 Monitors in Pthreads, 194 4.4.1 Pthreads Condition Variables, 196 4.4.2 Condition Variables in J2SE 5.0, 196 4.5 Signaling Disciplines, 199 4.5.1 Signal-and-Urgent-Wait, 199 4.5.2 Signal-and-Exit, 202 4.5.3 Urgent-Signal-and-Continue, 204 4.5.4 Comparing SU and SC Signals, 204 4.6 Using Semaphores to Implement Monitors, 206 4.6.1 SC Signaling, 206 4.6.2 SU Signaling, 207 4.7 Monitor Toolbox for Java, 209 4.7.1 Toolbox for SC Signaling in Java, 210 4.7.2 Toolbox for SU Signaling in Java, 210 4.8 Monitor Toolbox for Win32/C++/Pthreads, 211 4.8.1 Toolbox for SC Signaling in C++/Win32/Pthreads, 213 4.8.2 Toolbox for SU Signaling in C++/Win32/Pthreads, 213 4.9 Nested Monitor Calls, 213 4.10 Tracing and Replay for Monitors, 217 4.10.1 Simple M-Sequences, 217 4.10.2 Tracing and Replaying Simple M-Sequences, 219 4.10.3 Other Approaches to Program Replay, 220 4.11 Testing Monitor-Based Programs, 222 4.11.1 M-Sequences, 222 4.11.2 Determining the Feasibility of an M-Sequence, 227 4.11.3 Determining the Feasibility of a Communication-Sequence, 233 4.11.4 Reachability Testing for Monitors, 233 4.11.5 Putting It All Together, 235 Further Reading, 243 References, 243 Exercises, 245 5 Message Passing 5.1 Channel Objects, 258 5.1.1 Channel Objects in Java, 259 5.1.2 Channel Objects in C++/Win32, 263 5.2 Rendezvous, 266 5.3 Selective Wait, 272

258

CONTENTS

ix

5.4 Message-Based Solutions to Concurrent Programming Problems, 275 5.4.1 Readers and Writers, 275 5.4.2 Resource Allocation, 278 5.4.3 Simulating Counting Semaphores, 281 5.5 Tracing, Testing, and Replay for Message-Passing Programs, 281 5.5.1 SR-Sequences, 282 5.5.2 Simple SR-Sequences, 288 5.5.3 Determining the Feasibility of an SR-Sequence, 290 5.5.4 Deterministic Testing, 296 5.5.5 Reachability Testing for Message-Passing Programs, 297 5.5.6 Putting It All Together, 299 Further Reading, 304 References, 304 Exercises, 304 6 Message Passing in Distributed Programs 6.1 TCP Sockets, 312 6.1.1 Channel Reliability, 313 6.1.2 TCP Sockets in Java, 314 6.2 Java TCP Channel Classes, 317 6.2.1 Classes TCPSender and TCPMailbox, 318 6.2.2 Classes TCPSynchronousSender and TCPSynchronousMailbox, 326 6.2.3 Class TCPSelectableSynchronousMailbox, 328 6.3 Timestamps and Event Ordering, 329 6.3.1 Event-Ordering Problems, 330 6.3.2 Local Real-Time Clocks, 331 6.3.3 Global Real-Time Clocks, 332 6.3.4 Causality, 332 6.3.5 Integer Timestamps, 334 6.3.6 Vector Timestamps, 335 6.3.7 Timestamps for Programs Using Messages and Shared Variables, 339 6.4 Message-Based Solutions to Distributed Programming Problems, 341 6.4.1 Distributed Mutual Exclusion, 341 6.4.2 Distributed Readers and Writers, 346 6.4.3 Alternating Bit Protocol, 348 6.5 Testing and Debugging Distributed Programs, 353 6.5.1 Object-Based Sequences, 353 6.5.2 Simple Sequences, 362

312

x

CONTENTS

6.5.3 Tracing, Testing, and Replaying CARC-Sequences and CSC-Sequences, 362 6.5.4 Putting It All Together, 369 6.5.5 Other Approaches to Replaying Distributed Programs, 371 Further Reading, 374 References, 375 Exercises, 376 7 Testing and Debugging Concurrent Programs

381

7.1 Synchronization Sequences of Concurrent Programs, 383 7.1.1 Complete Events vs. Simple Events, 383 7.1.2 Total Ordering vs. Partial Ordering, 386 7.2 Paths of Concurrent Programs, 388 7.2.1 Defining a Path, 388 7.2.2 Path-Based Testing and Coverage Criteria, 391 7.3 Definitions of Correctness and Faults for Concurrent Programs, 395 7.3.1 Defining Correctness for Concurrent Programs, 395 7.3.2 Failures and Faults in Concurrent Programs, 397 7.3.3 Deadlock, Livelock, and Starvation, 400 7.4 Approaches to Testing Concurrent Programs, 408 7.4.1 Nondeterministic Testing, 409 7.4.2 Deterministic Testing, 410 7.4.3 Combinations of Deterministic and Nondeterministic Testing, 414 7.5 Reachability Testing, 419 7.5.1 Reachability Testing Process, 420 7.5.2 SYN-Sequences for Reachability Testing, 424 7.5.3 Race Analysis of SYN-Sequences, 429 7.5.4 Timestamp Assignment, 433 7.5.5 Computing Race Variants, 439 7.5.6 Reachability Testing Algorithm, 441 7.5.7 Research Directions, 447 Further Reading, 449 References, 449 Exercises, 452 Index

457

PREFACE

This is a textbook on multithreaded programming. The objective of this book is to teach students about languages and libraries for multithreaded programming, to help students develop problem-solving and programming skills, and to describe and demonstrate various testing and debugging techniques that have been developed for multithreaded programs over the past 20 years. It covers threads, semaphores, locks, monitors, message passing, and the relevant parts of Java, the POSIX Pthreads library, and the Windows Win32 Application Programming Interface (API). The book is unique in that it provides in-depth coverage on testing and debugging multithreaded programs, a topic that typically receives little attention. The title Modern Multithreading reflects the fact that there are effective and relatively new testing and debugging techniques for multithreaded programs. The material in this book was developed in concurrent programming courses that the authors have taught for 20 years. This material includes results from the authors’ research in concurrent programming, emphasizing tools and techniques that are of practical use. A class library has been implemented to provide working examples of all the material that is covered. Classroom Use In our experience, students have a hard time learning to write concurrent programs. If they manage to get their programs to run, they usually encounter deadlocks and other intermittent failures, and soon discover how difficult it is to reproduce the failures and locate the cause of the problem. Essentially, they have no way to check the correctness of their programs, which interferes with learning. Instructors face the same problem when grading multithreaded programs. It xi

xii

PREFACE

is tedious, time consuming, and often impossible to assess student programs by hand. The class libraries that we have developed, and the testing techniques they support, can be used to assess student programs. When we assign programming problems in our courses, we also provide test cases that the students must use to assess the correctness of their programs. This is very helpful for the students and the instructors. This book is designed for upper-level undergraduates and graduate students in computer science. It can be used as a main text in a concurrent programming course or could be used as a supplementary text for an operating systems course or a software engineering course. Since the text emphasizes practical material, provides working code, and addresses testing and debugging problems that receive little or no attention in many other books, we believe that it will also be helpful to programmers in industry. The text assumes that students have the following background: ž ž ž

ž ž

Programming experience as typically gained in CS 1 and CS 2 courses. Knowledge of elementary data structures as learned in a CS 2 course. An understanding of Java fundamentals. Students should be familiar with object-oriented programming in Java, but no “advanced” knowledge is necessary. An understanding of C++ fundamentals. We use only the basic objectoriented programming features of C++. A prior course on operating systems is helpful but not required.

We have made an effort to minimize the differences between our Java and C++ programs. We use object-oriented features that are common to both languages, and the class library has been implemented in both languages. Although we don’t illustrate every example in both Java and C++, the differences are very minor and it is easy to translate program examples from one language to the other. Content The book has seven chapters. Chapter 1 defines operating systems terms such as process, thread, and context switch. It then shows how to create threads, first in Java and then in C++ using both the POSIX Pthreads library and the Win32 API. A C++ Thread class is provided to hide the details of thread creation in Pthreads/Win32. C++ programs that use the Thread class look remarkably similar to multithreaded Java programs. Fundamental concepts, such as atomicity and nondeterminism, are described using simple program examples. Chapter 1 ends by listing the issues and problems that arise when testing and debugging multithreaded programs. To illustrate the interesting things to come, we present a simple multithreaded C++ program that is capable of tracing and replaying its own executions. Chapter 2 introduces concurrent programming by describing various solutions to the critical section problem. This problem is easy to understand but hard

PREFACE

xiii

to solve. The advantage of focusing on this problem is that it can be solved without introducing complicated new programming constructs. Students gain a quick appreciation for the programming skills that they need to acquire. Chapter 2 also demonstrates how to trace and replay Peterson’s solution to the critical section problem, which offers a straightforward introduction to several testing and debugging issues. The synchronization library implements the various techniques that are described. Chapters 3, 4, and 5 cover semaphores, monitors and message passing, respectively. Each chapter describes one of these constructs and shows how to use it to solve programming problems. Semaphore and Lock classes for Java and C++/Win32/Pthreads are presented in Chapter 3. Chapter 4 presents monitor classes for Java and C++/Win32/Pthreads. Chapter 5 presents mailbox classes with send/receive methods and a selective wait statement. These chapters also cover the built-in support that Win32 and Pthreads provide for these constructs, as well as the support provided by J2SE 5.0 (Java 2 Platform, Standard Edition 5.0). Each chapter addresses a particular testing or debugging problem and shows how to solve it. The synchronization library implements the testing and debugging techniques so that students can apply them to their own programs. Chapter 6 covers message passing in a distributed environment. It presents several Java mailbox classes that hide the details of TCP message passing and shows how to solve several distributed programming problems in Java. It also shows how to test and debug programs in a distributed environment (e.g., accurately tracing program executions by using vector timestamps). This chapter by no means provides complete coverage of distributed programming. Rather, it is meant to introduce students to the difficulty of distributed programming and to show them that the testing and debugging techniques presented in earlier chapters can be extended to work in a distributed environment. The synchronization library implements the various techniques. Chapter 7 covers concepts that are fundamental to testing and debugging concurrent programs. It defines important terms, presents several test coverage criteria for concurrent programs, and describes the various approaches to testing concurrent programs. This chapter organizes and summarizes the testing and debugging material that is presented in depth in Chapters 2 to 6. This organization provides two paths through the text. Instructors can cover the testing and debugging material in the last sections of Chapters 2 to 6 as they go through those chapters, or they can cover those sections when they cover Chapter 7. Chapter 7 also discusses reachability testing, which offers a bridge between testing and verification, and is implemented in the synchronization library. Each chapter has exercises at the end. Some of the exercises explore the concepts covered in the chapter, whereas others require a program to be written. In our courses we cover all the chapters and give six homework assignments, two in-class exams, and a project. We usually supplement the text with readings on model checking, process algebra, specification languages, and other research topics.

xiv

PREFACE

Online Resources The home page for this book is located at http://www.cs.gmu.edu/∼rcarver/ModernMultithreading This Web site contains the source code for all the listings in the text and for the synchronization libraries. It also contains startup files and test cases for some of the exercises. Solutions to the exercises are available for instructors, as is a copy of our lecture notes. There will also be an errata page. Acknowledgments The suggestions we received from the anonymous reviewers were very helpful. The National Science Foundation supported our research through grants CCR-8907807, CCR-9320992, CCR-9309043, and CCR-9804112. We thank our research assistants and the students in our courses at North Carolina State and George Mason University for helping us solve many interesting problems. We also thank Professor Jeff Lei at the University of Texas at Arlington for using early versions of this book in his courses. My friend, colleague, and coauthor Professor K. C. Tai passed away before we could complete this book. K.C. was an outstanding teacher, a world-class researcher in the areas of software engineering, concurrent systems, programming languages, and compiler construction, and an impeccable and highly respected professional. If the reader finds this book helpful, it is a tribute to K.C.’s many contributions. Certainly, K.C. would have fixed the faults that I failed to find. RICHARD H. CARVER Fairfax, Virginia July 2005 [email protected]

1 INTRODUCTION TO CONCURRENT PROGRAMMING

A concurrent program contains two or more threads that execute concurrently and work together to perform some task. In this chapter we begin with an operating system’s view of a concurrent program. The operating system manages the program’s use of hardware and software resources and allows the program’s threads to share the central processing units (CPUs). We then learn how to define and create threads in Java and also in C++ using the Windows Win32 API and the POSIX Pthreads library. Java provides a Thread class, so multithreaded Java programs are object-oriented. Win32 and Pthreads provide a set of function calls for creating and manipulating threads. We wrap a C++ Thread class around these functions so that we can write C++/Win32 and C++/Pthreads multithreaded programs that have the same object-oriented structure as Java programs. All concurrent programs exhibit unpredictable behavior. This creates new challenges for programmers, especially those learning to write concurrent programs. In this chapter we learn the reason for this unpredictable behavior and examine the problems it causes during testing and debugging.

1.1 PROCESSES AND THREADS: AN OPERATING SYSTEM’S VIEW When a program is executed, the operating system creates a process containing the code and data of the program and manages the process until the program terminates. User processes are created for user programs, and system processes Modern Multithreading: Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs, By Richard H. Carver and Kuo-Chung Tai Copyright  2006 John Wiley & Sons, Inc.

1

2

INTRODUCTION TO CONCURRENT PROGRAMMING

are created for system programs. A user process has its own logical address space, separate from the space of other user processes and separate from the space (called the kernel space) of the system processes. This means that two processes may reference the same logical address, but this address will be mapped to different physical memory locations. Thus, processes do not share memory unless they make special arrangements with the operating system to do so. Multiprocessing operating systems enable several programs to execute simultaneously. The operating system is responsible for allocating the computer’s resources among competing processes. These shared resources include memory, peripheral devices such as printers, and the CPU(s). The goal of a multiprocessing operating system is to have some process executing at all times in order to maximize CPU utilization. Within a process, program execution entails initializing and maintaining a great deal of information [Anderson et al. 1989]. For instance: ž ž ž ž

The process state (e.g., ready, running, waiting, or stopped) The program counter, which contains the address of the next instruction to be executed for this process Saved CPU register values Memory management information (page tables and swap files), file descriptors, and outstanding input/output (I/O) requests

The volume of this per-process information makes it expensive to create and manage processes. A thread is a unit of control within a process. When a thread runs, it executes a function in the program. The process associated with a running program starts with one running thread, called the main thread, which executes the “main” function of the program. In a multithreaded program, the main thread creates other threads, which execute other functions. These other threads can create even more threads, and so on. Threads are created using constructs provided by the programming language or the functions provided by an application programming interface (API). Each thread has its own stack of activation records and its own copy of the CPU registers, including the stack pointer and the program counter, which together describe the state of the thread’s execution. However, the threads in a multithreaded process share the data, code, resources, and address space of their process. The per-process state information listed above is also shared by the threads in the program, which greatly reduces the overhead involved in creating and managing threads. In Win32 a program can create multiple processes or multiple threads. Since thread creation in Win32 has lower overhead, we focus on single-process multithreaded Win32 programs. The operating system must decide how to allocate the CPUs among the processes and threads in the system. In some systems, the operating system selects a process to run and the process selected chooses which of its threads will execute. Alternatively, the threads are scheduled directly by the operating system. At any

ADVANTAGES OF MULTITHREADING

3

given moment, multiple processes, each containing one or more threads, may be executing. However, some threads may not be ready for execution. For example, some threads may be waiting for an I/O request to complete. The scheduling policy determines which of the ready threads is selected for execution. In general, each ready thread receives a time slice (called a quantum) of the CPU. If a thread decides to wait for something, it relinquishes the CPU voluntarily. Otherwise, when a hardware timer determines that a running thread’s quantum has completed, an interrupt occurs and the thread is preempted to allow another ready thread to run. If there are multiple CPUs, multiple threads can execute at the same time. On a computer with a single CPU, threads have the appearance of executing simultaneously, although they actually take turns running and they may not receive equal time. Hence, some threads may appear to run at a faster rate than others. The scheduling policy may also consider a thread’s priority and the type of processing that the thread performs, giving some threads preference over others. We assume that the scheduling policy is fair, which means that every ready thread eventually gets a chance to execute. A concurrent program’s correctness should not depend on its threads being scheduled in a certain order. Switching the CPU from one process or thread to another, known as a context switch, requires saving the state of the old process or thread and loading the state of the new one. Since there may be several hundred context switches per second, context switches can potentially add significant overhead to an execution.

1.2 ADVANTAGES OF MULTITHREADING Multithreading allows a process to overlap I/O and computation. One thread can execute while another thread is waiting for an I/O operation to complete. Multithreading makes a GUI (graphical user interface) more responsive. The thread that handles GUI events, such as mouse clicks and button presses, can create additional threads to perform long-running tasks in response to the events. This allows the event handler thread to respond to more GUI events. Multithreading can speed up performance through parallelism. A program that makes full use of two processors may run in close to half the time. However, this level of speedup usually cannot be obtained, due to the communication overhead required for coordinating the threads (see Exercise 1.11). Multithreading has some advantages over multiple processes. Threads require less overhead to manage than processes, and intraprocess thread communication is less expensive than interprocess communication. Multiprocess concurrent programs do have one advantage: Each process can execute on a different machine (in which case, each process is often a multithreaded program). This type of concurrent program is called a distributed program. Examples of distributed programs are file servers (e.g., NFS), file transfer clients and servers (e.g., FTP), remote log-in clients and servers (e.g., Telnet), groupware programs, and Web browsers and servers. The main disadvantage of concurrent programs is that they

4

INTRODUCTION TO CONCURRENT PROGRAMMING

are extremely difficult to develop. Concurrent programs often contain bugs that are notoriously difficult to find and fix. Once we have examined several concurrent programs, we’ll take a closer look at the special problems that arise when we test and debug them. 1.3 THREADS IN JAVA A Java program has a main thread that executes the main() function. In addition, several system threads are started automatically whenever a Java program is executed. Thus, every Java program is a concurrent program, although the programmer may not be aware that multiple threads are running. Java provides a Thread class for defining user threads. One way to define a thread is to define a class that extends (i.e., inherits from) the Thread class. Class simpleThread in Listing 1.1 extends class Thread. Method run() contains the code that will be executed when a simpleThread is started. The default run() method inherited from class Thread is empty, so a new run() method must be defined in simpleThread in order for the thread to do something useful. The main thread creates simpleThreads named thread1 and thread2 and starts them. (These threads continue to run after the main thread completes its statements.) Threads thread1 and thread2 each display a simple message and terminate. The integer IDs passed as arguments to the simpleThread constructor are used to distinguish between the two instances of simpleThread. A second way to define a user thread in Java is to use the Runnable interface. Class simpleRunnable in Listing 1.2 implements the Runnable interface, which means that simpleRunnable must provide an implementation of method run(). The main method creates a Runnable instance r of class simpleRunnable, passes r as an argument to the Thread class constructor for thread3, and starts thread3. Using a Runnable object to define the run() method offers one advantage over extending class Thread. Since class simpleRunnable implements interface Runnable, it is not required to extend class Thread, which means that class simpleThread extends Thread { public simpleThread(int ID) {myID = ID;} public void run() {System.out.println(‘‘Thread ’’ + myID + ‘‘ is running.’’);} private int myID; } public class javaConcurrentProgram { public static void main(String[] args) { simpleThread thread1 = new simpleThread(1); simpleThread thread2 = new simpleThread(2); thread1.start(); thread2.start(); // causes the run() methods to execute } } Listing 1.1

Simple concurrent Java program.

5

THREADS IN JAVA

class simpleRunnable implements Runnable { public simpleRunnable(int ID) {myID = ID;} public void run() {System.out.println(‘‘Thread ’’ + myID + ‘‘ is running.’’);} private int myID; } public class javaConcurrentProgram2 { public static void main(String[] args) { Runnable r = new simpleRunnable(3); Thread thread3 = new Thread(r); // thread3 executed r’s run() method thread3.start(); } } Listing 1.2

Java’s Runnable interface.

simpleRunnable could, if desired, extend some other class. This is important since a Java class cannot extend more than one other class. (A Java class can implement one or more interfaces but can extend only one class.) The details about how Java threads are scheduled vary from system to system. Java threads can be assigned a priority, which affects how threads are selected for execution. Using method setPriority(), a thread T can be assigned a priority in a range from Thread.MIN PRIORITY (usually, 1) to Thread.MAX PRIORITY (usually, 10): T.setPriority(6);

Higher-priority threads get preference over lower-priority threads, but it is difficult to make more specific scheduling guarantees based only on thread priorities. We will not be assigning priorities to the threads in this book, which means that user threads will always have the same priority. However, even if all the threads have the same priority, a thread may not be certain to get a chance to run. Consider a thread that is executing the following infinite loop: while (true) { ; }

This loop contains no I/O statements or any other statements that require the thread to release the CPU voluntarily. In this case the operating system must preempt the thread to allow other threads to run. Java does not guarantee that the underlying thread scheduling policy is preemptive. Thus, once a thread begins executing this loop, there is no guarantee that any other threads will execute. To be safe, we can add a sleep statement to this loop: while (true) { try {Thread.sleep(100);}

// delay thread for 100 milliseconds // (i.e., 0.1 second)

6

INTRODUCTION TO CONCURRENT PROGRAMMING

catch (InterruptedException e) {}

// InterruptedException must be caught // when sleep() is called

}

Executing the sleep() statement will force a context switch, giving the other threads a chance to run. In this book we assume that the underlying thread scheduling policy is preemptive, so that sleep() statements are not necessary to ensure fair scheduling. However, since sleep() statements have a dramatic effect on execution, we will see later that they can be very useful during testing.

1.4 THREADS IN Win32 Multithreaded programs in Windows use the functions in the Win32 API. Threads are created by calling function CreateThread() or function beginthreadex(). If a program needs to use the multithreaded C run-time library, it should use beginthreadex() to create threads; otherwise, it can use CreateThread(). Whether a program needs to use the multithreaded C run-time library depends on which of the library functions it calls. Some of the functions in the single-threaded runtime library may not work properly in a multithreaded program. This includes functions malloc() and free() (or new and delete in C++), any of the functions in stdio.h or io.h, and functions such as asctime(), strtok(), and rand(). For the sake of simplicity and safety, we use only beginthreadex() in this book. (Since the parameters for beginthreadex() and CreateThread() are almost identical, we will essentially be learning how to use both functions.) Details about choosing between the single- and multithreaded C run-time libraries can be found in [Beveridge and Wiener 1997]. Function beginthreadex() takes six parameters and returns a pointer, called a handle, to the newly created thread. This handle must be saved so that it can be passed to other Win32 functions that manipulate threads: unsigned long _beginthreadex( void* security, // security attribute unsigned stackSize, // size of the thread’s stack unsigned ( __stdcall *funcStart ) (void *), // starting address of the function // to run void* argList, // arguments to be passed to the // thread unsigned initFlags, // initial state of the thread: running // or suspended unsigned* threadAddr // thread ID );

THREADS IN Win32

7

The parameters of function beginthreadex() are as follows: ž ž

ž ž ž

ž

security: a security attribute, which in our programs is always the default value NULL. stackSize: the size, in bytes, of the new thread’s stack. We will use the default value 0, which specifies that the stack size defaults to the stack size of the main thread. funcStart: the (address of a) function that the thread will execute. (This function plays the same role as the run() method in Java.) argList: an argument to be passed to the thread. This is either a 32-bit value or a 32-bit pointer to a data structure. The Win32 type for void* is LPVOID. initFlags: a value that is either 0 or CREATE SUSPENDED. The value 0 specifies that the thread should begin execution immediately upon creation. The value CREATE SUSPENDED specifies that the thread is suspended immediately after it is created and will not run until the Win32 function ResumeThread (HANDLE hThread) is called on it. threadAddr: the address of a memory location that will receive an identifier assigned to the thread by Win32.

If beginthreadex() is successful, it returns a valid thread handle, which must be cast to the Win32 type HANDLE to be used in other functions. It returns 0 if it fails. The program in Listing 1.3 is a C++/Win32 version of the simple Java program in Listing 1.1. Array threadArray stores the handles for the two threads created in main(). Each thread executes the code in function simpleThread(), which displays the ID assigned by the user and returns the ID. Thread IDs are integers that the user supplies as the fourth argument on the call to function beginthreadex(). Function beginthreadex() forwards the IDs as arguments to thread function simpleThread() when the threads are created. Threads created in main() will not continue to run after the main thread exits. Thus, the main thread must wait for both of the threads it created to complete before it exits the main() function. (This behavior is opposite that of Java’s main() method.) It does this by calling function WaitForMultipleObjects(). The second argument to WaitForMultipleObjects() is the array that holds the thread handles, and the first argument is the size of this array. The third argument TRUE indicates that the function will wait for all of the threads to complete. If FALSE were used instead, the function would wait until any one of the threads completed. The fourth argument is a timeout duration in milliseconds. The value INFINITE means that there is no time limit on how long WaitForMultipleObjects() should wait for the threads to complete. When both threads have completed, function GetExitCodeThread() is used to capture the return values of the threads.

8

INTRODUCTION TO CONCURRENT PROGRAMMING

#include #include #include // needed for function _beginthreadex() void PrintError(LPTSTR lpszFunction,LPSTR fileName, int lineNumber) { TCHAR szBuf[256]; LPSTR lpErrorBuf; DWORD errorCode = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpErrorBuf, 0, NULL ); wsprintf(szBuf, "%s failed at line %d in %s with error %d: %s", lpszFunction, lineNumber, fileName, errorCode, lpErrorBuf); DWORD numWritten; WriteFile(GetStdHandle(STD_ERROR_HANDLE),szBuf,strlen(szBuf), &numWritten,FALSE); LocalFree(lpErrorBuf); exit(errorCode); } unsigned WINAPI simpleThread (LPVOID myID) { // myID receives the 4th argument of _beginthreadex(). // Note: ‘‘WINAPI’’ refers to the ‘‘__stdcall’’ calling convention // API functions, and ‘‘LPVOID’’ is a Win32 data type defined as void* std::cout result = aThread->run(); aThread->setCompleted(); return reinterpret_cast(aThread->result); } void* Thread::join() { DWORD rc = WaitForSingleObject( completionEvent, // handle to event INFINITE); // no timeout if (!(rc==WAIT_OBJECT_0)) PrintError("WaitForSingleObject failed at ",__FILE__,__LINE__); return result; } void Thread::setCompleted() { DWORD rc = SetEvent(completionEvent); if (!rc) PrintError("SetEvent failed at ",__FILE__,__LINE__); } Listing 3.25 Event object in the Win32 Thread class.

setCompleted() to set the thread’s status to completed and to notify any threads waiting in join() that the thread has completed. Methods setCompleted() and join() are implemented using an Event called completionEvent that is created in the Thread class constructor. A thread calling T.join() is blocked on

134

SEMAPHORES AND LOCKS

completionEvent if T has not yet completed. The call to setCompleted() releases all threads that are blocked on completionEvent and leaves completionEvent in the signaled state. Since the completionEvent is never reset, threads that call join() after setCompleted() is called are not blocked. If completionEvent were an auto-reset Event, a call to setCompleted() would release all the waiting threads and reset completionEvent to the nonsignaled state. This would cause a problem since any threads that then called T.join() would be blocked forever even though thread T had already completed. 3.7.5 Other Synchronization Functions The WaitForMultipleObjects() function was described in Section 1.4, where it was used in the main thread to wait for child threads to finish. Threads are kernel objects and thus are either in the signaled or nonsignaled state. When a thread is created and running, its state is nonsignaled. When the thread terminates, it becomes signaled. The SignalObjectAndWait() function allows the caller to signal an object atomically and wait on another object. When used with semaphores, it is equivalent to the VP() operation defined in Section 3.4.2. DWORD SignalObjectAndWait( HANDLE HANDLE DWORD BOOL

// handle to object for signal // handle to object for wait // timeout interval // alertable option: specifies whether the // wait state can be aborted

);

Function SignalObjectAndWait() is available in Windows NT/2000 4.0 and higher. It is not supported in Windows 95/98. 3.7.6 Example: C++/Win32 Bounded Buffer Listing 3.26 is a Win32 solution to the bounded buffer problem that is based on the Java version in Listing 3.17. Notice that Semaphores fullSlots and emptySlots and locks mutexD and mutexW, which protect the Buffer, are declared outside the Buffer class. A better design would be to encapsulate the Semaphores within class Buffer. We will save this improvement for Chapter 4, where we also address some of the difficulties of programming with Semaphores.

3.8 SEMAPHORES AND LOCKS IN PTHREADS Mutex locks are part of the Pthreads (POSIX1.c) standard. Semaphores are not a part of Pthreads, but are in POSIX1.b.

SEMAPHORES AND LOCKS IN PTHREADS

135

const int capacity = 3; class Buffer { private: int buffer[capacity]; int count, in, out; public: Buffer() : in(0), out(0), count(0) { } int size() { return count;} int withdraw () { int value = 0; value = buffer[out]; // out is shared by Consumers out = (out + 1) % capacity; count--; return value; } void deposit (int value) { buffer[in] = value; // in is shared by Producers in = (in + 1) % capacity; count++; } }; Buffer sharedBuffer; // 3-slot buffer mutexLock mutexD, mutexW; countingSemaphore emptySlots(capacity); countingSemaphore fullSlots(0); class Producer : public Thread { public: virtual void* run () { int i; std::cout