Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add AIAccessConst, AISTAccess, AISTAccessConst, ...

Also added AIThreadSafeSingleThread, AIThreadSafeSingleThreadDC
and AITHREADSAFESINGLETHREAD
  • Loading branch information...
commit b18bc0860083e6367b6562c169261a394cae1469 1 parent fffbda1
AlericInglewood authored March 13, 2012

Showing 1 changed file with 201 additions and 10 deletions. Show diff stats Hide diff stats

  1. 211  indra/llcommon/aithreadsafe.h
211  indra/llcommon/aithreadsafe.h
@@ -49,7 +49,10 @@
49 49
 template<typename T> struct AIReadAccessConst;
50 50
 template<typename T> struct AIReadAccess;
51 51
 template<typename T> struct AIWriteAccess;
  52
+template<typename T> struct AIAccessConst;
52 53
 template<typename T> struct AIAccess;
  54
+template<typename T> struct AISTAccessConst;
  55
+template<typename T> struct AISTAccess;
53 56
 
54 57
 #if LL_WINDOWS
55 58
 template<typename T> class AIThreadSafeBits;
@@ -398,6 +401,7 @@ class AIThreadSafeSimple : public AIThreadSafeBits<T>
398 401
 {
399 402
 protected:
400 403
 	// Only this one may access the object (through ptr()).
  404
+	friend struct AIAccessConst<T>;
401 405
 	friend struct AIAccess<T>;
402 406
 
403 407
 	// Locking control.
@@ -509,13 +513,13 @@ class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase,
509 513
 };
510 514
 
511 515
 /**
512  
- * @brief Write lock object and provide read/write access.
  516
+ * @brief Write lock object and provide read access.
513 517
  */
514 518
 template<typename T>
515  
-struct AIAccess
  519
+struct AIAccessConst
516 520
 {
517  
-	//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
518  
-	AIAccess(AIThreadSafeSimple<T>& wrapper) : mWrapper(wrapper)
  521
+	//! Construct a AIAccessConst from a constant AIThreadSafeSimple.
  522
+	AIAccessConst(AIThreadSafeSimple<T> const& wrapper) : mWrapper(const_cast<AIThreadSafeSimple<T>&>(wrapper))
519 523
 #if AI_NEED_ACCESS_CC
520 524
 		, mIsCopyConstructed(false)
521 525
 #endif
@@ -524,12 +528,12 @@ struct AIAccess
524 528
 	}
525 529
 
526 530
 	//! Access the underlaying object for (read and) write access.
527  
-	T* operator->() const { return this->mWrapper.ptr(); }
  531
+	T const* operator->() const { return this->mWrapper.ptr(); }
528 532
 
529 533
 	//! Access the underlaying object for (read and) write access.
530  
-	T& operator*() const { return *this->mWrapper.ptr(); }
  534
+	T const& operator*() const { return *this->mWrapper.ptr(); }
531 535
 
532  
-	~AIAccess()
  536
+	~AIAccessConst()
533 537
 	{
534 538
 #if AI_NEED_ACCESS_CC
535 539
 	  if (mIsCopyConstructed) return;
@@ -538,17 +542,204 @@ struct AIAccess
538 542
 	}
539 543
 
540 544
 protected:
541  
-	AIThreadSafeSimple<T>& mWrapper;	//!< Reference to the object that we provide access to.
  545
+	AIThreadSafeSimple<T>& mWrapper;		//!< Reference to the object that we provide access to.
542 546
 
543 547
 #if AI_NEED_ACCESS_CC
544 548
 	bool mIsCopyConstructed;
545 549
 public:
546  
-	AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
  550
+	AIAccessConst(AIAccessConst const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
  551
+#else
  552
+private:
  553
+	// Disallow copy constructing directly.
  554
+	AIAccessConst(AIAccessConst const&);
  555
+#endif
  556
+};
  557
+
  558
+/**
  559
+ * @brief Write lock object and provide read/write access.
  560
+ */
  561
+template<typename T>
  562
+struct AIAccess : public AIAccessConst<T>
  563
+{
  564
+	//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
  565
+	AIAccess(AIThreadSafeSimple<T>& wrapper) : AIAccessConst<T>(wrapper) { }
  566
+
  567
+	//! Access the underlaying object for (read and) write access.
  568
+	T* operator->() const { return this->mWrapper.ptr(); }
  569
+
  570
+	//! Access the underlaying object for (read and) write access.
  571
+	T& operator*() const { return *this->mWrapper.ptr(); }
  572
+};
  573
+
  574
+/**
  575
+ * @brief A wrapper class for objects that should only be accessed by a single thread.
  576
+ *
  577
+ * Use AITHREADSAFESINGLETHREAD to define instances of any type, and use AISTAccess
  578
+ * to get access to the instance.
  579
+ *
  580
+ * For example,
  581
+ *
  582
+ * <code>
  583
+ * class Foo { public: Foo(int, int); };
  584
+ *
  585
+ * AITHREADSAFESINGLETHREAD(Foo, foo, (2, 3));
  586
+ *
  587
+ * AISTAccess<Foo> foo_w(foo);
  588
+ * // Use foo_w-> for read and write access.
  589
+ */
  590
+template<typename T>
  591
+class AIThreadSafeSingleThread : public AIThreadSafeBits<T>
  592
+{
  593
+protected:
  594
+	// Only these one may access the object (through ptr()).
  595
+	friend struct AISTAccessConst<T>;
  596
+	friend struct AISTAccess<T>;
  597
+
  598
+	// For use by AIThreadSafeSingleThreadDC.
  599
+	AIThreadSafeSingleThread(void)
  600
+#ifdef LL_DEBUG
  601
+	  : mAccessed(false)
  602
+#endif
  603
+	{ }
  604
+
  605
+#ifdef LL_DEBUG
  606
+	mutable bool mAccessed;
  607
+	mutable apr_os_thread_t mTheadID;
  608
+
  609
+	void accessed(void) const
  610
+	{
  611
+	  if (!mAccessed)
  612
+	  {
  613
+		mAccessed = true;
  614
+		mTheadID = apr_os_thread_current();
  615
+	  }
  616
+	  else
  617
+	  {
  618
+		llassert_always(apr_os_thread_equal(mTheadID, apr_os_thread_current()));
  619
+	  }
  620
+	}
  621
+#endif
  622
+
  623
+public:
  624
+	// Only for use by AITHREADSAFESINGLETHREAD, see below.
  625
+	AIThreadSafeSingleThread(T* object)
  626
+#ifdef LL_DEBUG
  627
+	  : mAccessed(false)
  628
+#endif
  629
+	{
  630
+	  llassert(object == AIThreadSafeBits<T>::ptr());
  631
+	}
  632
+};
  633
+
  634
+/**
  635
+ * @brief A wrapper class for objects that should only be accessed by a single thread.
  636
+ *
  637
+ * This class is the same as an AIThreadSafeSingleThread wrapper, except that it can only
  638
+ * be used for default constructed objects.
  639
+ *
  640
+ * For example, instead of
  641
+ *
  642
+ * <code>
  643
+ * Foo foo;
  644
+ * </code>
  645
+ *
  646
+ * One would use
  647
+ *
  648
+ * <code>
  649
+ * AIThreadSafeSingleThreadDC<Foo> foo;
  650
+ * </code>
  651
+ *
  652
+ * The advantage over AITHREADSAFESINGLETHREAD is that this object can be allocated with
  653
+ * new on the heap. For example:
  654
+ *
  655
+ * <code>
  656
+ * AIThreadSafeSingleThreadDC<Foo>* ptr = new AIThreadSafeSingleThreadDC<Foo>;
  657
+ * </code>
  658
+ *
  659
+ * which is not possible with AITHREADSAFESINGLETHREAD.
  660
+ */
  661
+template<typename T>
  662
+class AIThreadSafeSingleThreadDC : public AIThreadSafeSingleThread<T>
  663
+{
  664
+public:
  665
+	// Construct a wrapper around a default constructed object.
  666
+	AIThreadSafeSingleThreadDC(void) { new (AIThreadSafeSingleThread<T>::ptr()) T; }
  667
+};
  668
+
  669
+/**
  670
+ * @brief Instantiate a static, global or local object of a given type wrapped in AIThreadSafeSingleThread, using an arbitrary constructor.
  671
+ *
  672
+ * For example, instead of doing
  673
+ *
  674
+ * <code>
  675
+ * Foo foo(x, y);
  676
+ * static Bar bar;
  677
+ * </code>
  678
+ *
  679
+ * One can instantiate a thread-safe instance with
  680
+ *
  681
+ * <code>
  682
+ * AITHREADSAFESINGLETHREAD(Foo, foo, (x, y));
  683
+ * static AITHREADSAFESINGLETHREAD(Bar, bar, );
  684
+ * </code>
  685
+ *
  686
+ * Note: This macro does not allow to allocate such object on the heap.
  687
+ *       If that is needed, have a look at AIThreadSafeSingleThreadDC.
  688
+ */
  689
+#define AITHREADSAFESINGLETHREAD(type, var, paramlist) AIThreadSafeSingleThread<type> var(new (var.memory()) type paramlist)
  690
+
  691
+/**
  692
+ * @brief Access single threaded object for read access.
  693
+ */
  694
+template<typename T>
  695
+struct AISTAccessConst
  696
+{
  697
+	//! Construct a AISTAccessConst from a constant AIThreadSafeSingleThread.
  698
+	AISTAccessConst(AIThreadSafeSingleThread<T> const& wrapper) : mWrapper(const_cast<AIThreadSafeSingleThread<T>&>(wrapper))
  699
+	{
  700
+#if LL_DEBUG
  701
+	  wrapper.accessed();
  702
+#endif
  703
+	}
  704
+
  705
+	//! Access the underlaying object for read access.
  706
+	T const* operator->() const { return this->mWrapper.ptr(); }
  707
+
  708
+	//! Access the underlaying object for read write access.
  709
+	T const& operator*() const { return *this->mWrapper.ptr(); }
  710
+
  711
+protected:
  712
+	AIThreadSafeSingleThread<T>& mWrapper;		//!< Reference to the object that we provide access to.
  713
+
  714
+#if AI_NEED_ACCESS_CC
  715
+public:
  716
+	AISTAccessConst(AISTAccessConst const& orig) : mWrapper(orig.mWrapper) { }
547 717
 #else
548 718
 private:
549 719
 	// Disallow copy constructing directly.
550  
-	AIAccess(AIAccess const&);
  720
+	AISTAccessConst(AISTAccessConst const&);
551 721
 #endif
552 722
 };
553 723
 
  724
+/**
  725
+ * @brief Access single threaded object for read/write access.
  726
+ */
  727
+template<typename T>
  728
+struct AISTAccess : public AISTAccessConst<T>
  729
+{
  730
+	//! Construct a AISTAccess from a non-constant AIThreadSafeSingleThread.
  731
+	AISTAccess(AIThreadSafeSingleThread<T>& wrapper) : AISTAccessConst<T>(wrapper)
  732
+	{
  733
+#if LL_DEBUG
  734
+	  wrapper.accessed();
  735
+#endif
  736
+	}
  737
+
  738
+	//! Access the underlaying object for (read and) write access.
  739
+	T* operator->() const { return this->mWrapper.ptr(); }
  740
+
  741
+	//! Access the underlaying object for (read and) write access.
  742
+	T& operator*() const { return *this->mWrapper.ptr(); }
  743
+};
  744
+
554 745
 #endif

0 notes on commit b18bc08

Please sign in to comment.
Something went wrong with that request. Please try again.