1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP 2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP 3 4 // (C) Copyright 2006-8 Anthony Williams 5 // 6 // Distributed under the Boost Software License, Version 1.0. (See 7 // accompanying file LICENSE_1_0.txt or copy at 8 // http://www.boost.org/LICENSE_1_0.txt) 9 10 #include <boost/assert.hpp> 11 #include <boost/detail/interlocked.hpp> 12 #include <boost/thread/win32/thread_primitives.hpp> 13 #include <boost/static_assert.hpp> 14 #include <limits.h> 15 #include <boost/utility.hpp> 16 #include <boost/thread/thread_time.hpp> 17 18 #include <boost/config/abi_prefix.hpp> 19 20 namespace boost 21 { 22 class shared_mutex 23 { 24 private: 25 shared_mutex(shared_mutex const&); 26 shared_mutex& operator=(shared_mutex const&); 27 private: 28 struct state_data 29 { 30 unsigned shared_count:11, 31 shared_waiting:11, 32 exclusive:1, 33 upgrade:1, 34 exclusive_waiting:7, 35 exclusive_waiting_blocked:1; 36 operator ==(state_data const & lhs,state_data const & rhs)37 friend bool operator==(state_data const& lhs,state_data const& rhs) 38 { 39 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs); 40 } 41 }; 42 43 44 template<typename T> interlocked_compare_exchange(T * target,T new_value,T comparand)45 T interlocked_compare_exchange(T* target,T new_value,T comparand) 46 { 47 BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); 48 long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target), 49 *reinterpret_cast<long*>(&new_value), 50 *reinterpret_cast<long*>(&comparand)); 51 return *reinterpret_cast<T const*>(&res); 52 } 53 54 enum 55 { 56 unlock_sem = 0, 57 exclusive_sem = 1 58 }; 59 60 state_data state; 61 detail::win32::handle semaphores[2]; 62 detail::win32::handle upgrade_sem; 63 release_waiters(state_data old_state)64 void release_waiters(state_data old_state) 65 { 66 if(old_state.exclusive_waiting) 67 { 68 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); 69 } 70 71 if(old_state.shared_waiting || old_state.exclusive_waiting) 72 { 73 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); 74 } 75 } 76 77 78 public: shared_mutex()79 shared_mutex() 80 { 81 semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); 82 semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); 83 upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); 84 state_data state_={0}; 85 state=state_; 86 } 87 ~shared_mutex()88 ~shared_mutex() 89 { 90 detail::win32::CloseHandle(upgrade_sem); 91 detail::win32::CloseHandle(semaphores[unlock_sem]); 92 detail::win32::CloseHandle(semaphores[exclusive_sem]); 93 } 94 try_lock_shared()95 bool try_lock_shared() 96 { 97 state_data old_state=state; 98 for(;;) 99 { 100 state_data new_state=old_state; 101 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) 102 { 103 ++new_state.shared_count; 104 if(!new_state.shared_count) 105 { 106 return false; 107 } 108 } 109 110 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 111 if(current_state==old_state) 112 { 113 break; 114 } 115 old_state=current_state; 116 } 117 return !(old_state.exclusive| old_state.exclusive_waiting_blocked); 118 } 119 lock_shared()120 void lock_shared() 121 { 122 BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); 123 } 124 125 template<typename TimeDuration> timed_lock_shared(TimeDuration const & relative_time)126 bool timed_lock_shared(TimeDuration const & relative_time) 127 { 128 return timed_lock_shared(get_system_time()+relative_time); 129 } 130 timed_lock_shared(boost::system_time const & wait_until)131 bool timed_lock_shared(boost::system_time const& wait_until) 132 { 133 for(;;) 134 { 135 state_data old_state=state; 136 for(;;) 137 { 138 state_data new_state=old_state; 139 if(new_state.exclusive || new_state.exclusive_waiting_blocked) 140 { 141 ++new_state.shared_waiting; 142 if(!new_state.shared_waiting) 143 { 144 boost::throw_exception(boost::lock_error()); 145 } 146 } 147 else 148 { 149 ++new_state.shared_count; 150 if(!new_state.shared_count) 151 { 152 boost::throw_exception(boost::lock_error()); 153 } 154 } 155 156 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 157 if(current_state==old_state) 158 { 159 break; 160 } 161 old_state=current_state; 162 } 163 164 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) 165 { 166 return true; 167 } 168 169 unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until)); 170 if(res==detail::win32::timeout) 171 { 172 for(;;) 173 { 174 state_data new_state=old_state; 175 if(new_state.exclusive || new_state.exclusive_waiting_blocked) 176 { 177 if(new_state.shared_waiting) 178 { 179 --new_state.shared_waiting; 180 } 181 } 182 else 183 { 184 ++new_state.shared_count; 185 if(!new_state.shared_count) 186 { 187 return false; 188 } 189 } 190 191 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 192 if(current_state==old_state) 193 { 194 break; 195 } 196 old_state=current_state; 197 } 198 199 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) 200 { 201 return true; 202 } 203 return false; 204 } 205 206 BOOST_ASSERT(res==0); 207 } 208 } 209 unlock_shared()210 void unlock_shared() 211 { 212 state_data old_state=state; 213 for(;;) 214 { 215 state_data new_state=old_state; 216 bool const last_reader=!--new_state.shared_count; 217 218 if(last_reader) 219 { 220 if(new_state.upgrade) 221 { 222 new_state.upgrade=false; 223 new_state.exclusive=true; 224 } 225 else 226 { 227 if(new_state.exclusive_waiting) 228 { 229 --new_state.exclusive_waiting; 230 new_state.exclusive_waiting_blocked=false; 231 } 232 new_state.shared_waiting=0; 233 } 234 } 235 236 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 237 if(current_state==old_state) 238 { 239 if(last_reader) 240 { 241 if(old_state.upgrade) 242 { 243 BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0); 244 } 245 else 246 { 247 release_waiters(old_state); 248 } 249 } 250 break; 251 } 252 old_state=current_state; 253 } 254 } 255 lock()256 void lock() 257 { 258 BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); 259 } 260 261 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)262 bool timed_lock(TimeDuration const & relative_time) 263 { 264 return timed_lock(get_system_time()+relative_time); 265 } 266 try_lock()267 bool try_lock() 268 { 269 state_data old_state=state; 270 for(;;) 271 { 272 state_data new_state=old_state; 273 if(new_state.shared_count || new_state.exclusive) 274 { 275 return false; 276 } 277 else 278 { 279 new_state.exclusive=true; 280 } 281 282 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 283 if(current_state==old_state) 284 { 285 break; 286 } 287 old_state=current_state; 288 } 289 return true; 290 } 291 292 timed_lock(boost::system_time const & wait_until)293 bool timed_lock(boost::system_time const& wait_until) 294 { 295 for(;;) 296 { 297 state_data old_state=state; 298 299 for(;;) 300 { 301 state_data new_state=old_state; 302 if(new_state.shared_count || new_state.exclusive) 303 { 304 ++new_state.exclusive_waiting; 305 if(!new_state.exclusive_waiting) 306 { 307 boost::throw_exception(boost::lock_error()); 308 } 309 310 new_state.exclusive_waiting_blocked=true; 311 } 312 else 313 { 314 new_state.exclusive=true; 315 } 316 317 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 318 if(current_state==old_state) 319 { 320 break; 321 } 322 old_state=current_state; 323 } 324 325 if(!old_state.shared_count && !old_state.exclusive) 326 { 327 return true; 328 } 329 unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until)); 330 if(wait_res==detail::win32::timeout) 331 { 332 for(;;) 333 { 334 state_data new_state=old_state; 335 if(new_state.shared_count || new_state.exclusive) 336 { 337 if(new_state.exclusive_waiting) 338 { 339 if(!--new_state.exclusive_waiting) 340 { 341 new_state.exclusive_waiting_blocked=false; 342 } 343 } 344 } 345 else 346 { 347 new_state.exclusive=true; 348 } 349 350 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 351 if(current_state==old_state) 352 { 353 break; 354 } 355 old_state=current_state; 356 } 357 if(!old_state.shared_count && !old_state.exclusive) 358 { 359 return true; 360 } 361 return false; 362 } 363 BOOST_ASSERT(wait_res<2); 364 } 365 } 366 unlock()367 void unlock() 368 { 369 state_data old_state=state; 370 for(;;) 371 { 372 state_data new_state=old_state; 373 new_state.exclusive=false; 374 if(new_state.exclusive_waiting) 375 { 376 --new_state.exclusive_waiting; 377 new_state.exclusive_waiting_blocked=false; 378 } 379 new_state.shared_waiting=0; 380 381 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 382 if(current_state==old_state) 383 { 384 break; 385 } 386 old_state=current_state; 387 } 388 release_waiters(old_state); 389 } 390 lock_upgrade()391 void lock_upgrade() 392 { 393 for(;;) 394 { 395 state_data old_state=state; 396 for(;;) 397 { 398 state_data new_state=old_state; 399 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) 400 { 401 ++new_state.shared_waiting; 402 if(!new_state.shared_waiting) 403 { 404 boost::throw_exception(boost::lock_error()); 405 } 406 } 407 else 408 { 409 ++new_state.shared_count; 410 if(!new_state.shared_count) 411 { 412 boost::throw_exception(boost::lock_error()); 413 } 414 new_state.upgrade=true; 415 } 416 417 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 418 if(current_state==old_state) 419 { 420 break; 421 } 422 old_state=current_state; 423 } 424 425 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) 426 { 427 return; 428 } 429 430 BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite)); 431 } 432 } 433 try_lock_upgrade()434 bool try_lock_upgrade() 435 { 436 state_data old_state=state; 437 for(;;) 438 { 439 state_data new_state=old_state; 440 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) 441 { 442 return false; 443 } 444 else 445 { 446 ++new_state.shared_count; 447 if(!new_state.shared_count) 448 { 449 return false; 450 } 451 new_state.upgrade=true; 452 } 453 454 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 455 if(current_state==old_state) 456 { 457 break; 458 } 459 old_state=current_state; 460 } 461 return true; 462 } 463 unlock_upgrade()464 void unlock_upgrade() 465 { 466 state_data old_state=state; 467 for(;;) 468 { 469 state_data new_state=old_state; 470 new_state.upgrade=false; 471 bool const last_reader=!--new_state.shared_count; 472 473 if(last_reader) 474 { 475 if(new_state.exclusive_waiting) 476 { 477 --new_state.exclusive_waiting; 478 new_state.exclusive_waiting_blocked=false; 479 } 480 new_state.shared_waiting=0; 481 } 482 483 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 484 if(current_state==old_state) 485 { 486 if(last_reader) 487 { 488 release_waiters(old_state); 489 } 490 break; 491 } 492 old_state=current_state; 493 } 494 } 495 unlock_upgrade_and_lock()496 void unlock_upgrade_and_lock() 497 { 498 state_data old_state=state; 499 for(;;) 500 { 501 state_data new_state=old_state; 502 bool const last_reader=!--new_state.shared_count; 503 504 if(last_reader) 505 { 506 new_state.upgrade=false; 507 new_state.exclusive=true; 508 } 509 510 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 511 if(current_state==old_state) 512 { 513 if(!last_reader) 514 { 515 BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite)); 516 } 517 break; 518 } 519 old_state=current_state; 520 } 521 } 522 unlock_and_lock_upgrade()523 void unlock_and_lock_upgrade() 524 { 525 state_data old_state=state; 526 for(;;) 527 { 528 state_data new_state=old_state; 529 new_state.exclusive=false; 530 new_state.upgrade=true; 531 ++new_state.shared_count; 532 if(new_state.exclusive_waiting) 533 { 534 --new_state.exclusive_waiting; 535 new_state.exclusive_waiting_blocked=false; 536 } 537 new_state.shared_waiting=0; 538 539 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 540 if(current_state==old_state) 541 { 542 break; 543 } 544 old_state=current_state; 545 } 546 release_waiters(old_state); 547 } 548 unlock_and_lock_shared()549 void unlock_and_lock_shared() 550 { 551 state_data old_state=state; 552 for(;;) 553 { 554 state_data new_state=old_state; 555 new_state.exclusive=false; 556 ++new_state.shared_count; 557 if(new_state.exclusive_waiting) 558 { 559 --new_state.exclusive_waiting; 560 new_state.exclusive_waiting_blocked=false; 561 } 562 new_state.shared_waiting=0; 563 564 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 565 if(current_state==old_state) 566 { 567 break; 568 } 569 old_state=current_state; 570 } 571 release_waiters(old_state); 572 } 573 unlock_upgrade_and_lock_shared()574 void unlock_upgrade_and_lock_shared() 575 { 576 state_data old_state=state; 577 for(;;) 578 { 579 state_data new_state=old_state; 580 new_state.upgrade=false; 581 if(new_state.exclusive_waiting) 582 { 583 --new_state.exclusive_waiting; 584 new_state.exclusive_waiting_blocked=false; 585 } 586 new_state.shared_waiting=0; 587 588 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); 589 if(current_state==old_state) 590 { 591 break; 592 } 593 old_state=current_state; 594 } 595 release_waiters(old_state); 596 } 597 598 }; 599 } 600 601 #include <boost/config/abi_suffix.hpp> 602 603 #endif 604