SlideShare a Scribd company logo
Generic Synchronization Policies in C++ Ciaran McHale www.CiaranMcHale.com
License Copyright (c) 2006 Ciaran McHale Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Introduction Most people know that writing synchronization code is: Difficult: APIs are low-level Non-portable: many threading APIs: POSIX, Windows, Solaris, DCE, … In practice, most synchronization code implement a small number of high-level “usage patterns”: Let’s call these  generic synchronization policies  (GSPs) The most common GSPs can be implemented as a C++ library Using GSPs in applications: Is much easier than using low-level APIs Encapsulates the underlying threading package    provides portability
1. Scoped Locks
Critical section The following (pseudocode) function uses a critical section: void foo() { getLock(mutex); ...  releaseLock(mutex); } The above code is very simple. However… Complexity increases if the function has several exit points: Because  releaseLock()  must be called at each exit point Examples of extra exit points: Conditional  return  statements Conditionally throwing an exception
Critical section with multiple exit points void foo() { getLock(mutex); ... if (...) { releaseLock(mutex); return; } if (...) { releaseLock(mutex); throw anException; } ... releaseLock(mutex); } Have to call  releaseLock()  at every exit point from the function
Critique Needing to call  releaseLock()  at every exit point: Clutters up the “business logic” code with synchronization code This clutter makes code harder to read and maintain Forgetting to call  releaseLock()  at an exit point is a common source of bugs There is a better way…
Solution:  ScopedMutex  class Define a class called, say,  ScopedMutex : This class has no operations! Just a constructor and destructor Constructor calls  getLock()   Destructor calls  releaseLock()   Declare a  ScopedMutex  variable local to a function At entry to function    constructor is called    calls  getLock()   At exit from function    destructor is called    calls  releaseLock()   The following two slides show: Pseudocode implementation of  ScopedMutex  class Use of  ScopedMutex  in a function
The  ScopedMutex  class class ScopedMutex { public: ScopedMutex (Mutex & mutex) : m_mutex(mutex) { getLock(m_mutex); } ~ScopedMutex () { releaseLock(m_mutex); } private: Mutex & m_mutex; };
Use of  ScopedMutex void foo() { ScopedMutex  scopedLock(mutex); ... if (...) { return; } if (...) { throw anException; } ... } No need to call  releaseLock()  at every exit point from the function!
Comments on  ScopedMutex This technique is  partially  well known in the C++ community: 50% of developers the author worked with already knew this technique They considered it to be a “basic” C++ coding idiom Other 50% of developers had not seen the technique before Of the developers who already knew this technique: They all used it for mutex locks Only a few knew it could be used for readers-writer locks too Nobody knew it could be used for almost any type of synchronization code Contribution of this presentation: Generalize the technique so it can be used much more widely To explain how to do this, I need to take a slight detour: Have to introduce the concept of  generic synchronization policies
2. The Concept of Generic Synchronization Policies
Genericity for types C++ provides template types Example of a template type definition: template<t> class List { ... }; Examples of template type instantiation: List<int>  myIntList; List<double> myDoubleList; List<Widget> myWidgetList; Some other languages provide a similar capability, often with different terminology and syntax Perhaps called  generic types  instead of  template types   Perhaps surround type parameters with  []  instead of  <>
Genericity for synchronization policies Using a pseudocode notation, here are declarations of mutual exclusion and readers-writer policies Mutex[Op] RW[ReadOp, WriteOp] In above examples, each parameter is a set of operations Example instantiations on operations  Op1 ,  Op2  and  Op3   Mutex[{Op1, Op2, Op3}] RW[{Op1, Op2}, {Op3}]
Producer-consumer policy Useful when: A buffer is used to transfer data between threads A producer thread  puts  items into the buffer A consumer thread  gets  items from the buffer If the buffer is empty when the consumer tries to get an item then the consumer thread blocks The buffer might have  other  operations that examine the state of the buffer In pseudocode notation, the policy declaration is: ProdCons[PutOp, GetOp, OtherOp] Example instantiations: ProdCons[{insert}, {remove}, {count}] ProdCons[{insert}, {remove}, {}]
Bounded producer-consumer policy Variation of the producer-consumer policy: Buffer has a fixed size If the buffer is full when the producer tries to put in an item then the producer thread blocks In pseudocode notation, policy is: BoundedProdCons (int size) [PutOp, GetOp, OtherOp] Typically, the  size  parameter is instantiated on a parameter to the constructor of the buffer class An example instantiation will be shown later
3. Generic Synchronization Policies in C++
Mapping Mutex[Op] into C++ class  GSP_Mutex  { public: GSP_Mutex ()  {  /* initialize m_mutex */  } ~GSP_Mutex () {  /* destroy m_mutex */  } class Op { public: Op (GSP_Mutex & data) : m_data(data) {  getLock(m_data.m_mutex);  } ~Op () {  releaseLock(m_data.m_mutex);  } private: GSP_Mutex & m_data; }; private: friend class ::GSP_Mutex::Op; OS-specific-type m_mutex; }; Constructor & destructor of nested class  get  and  release  locks stored in the outer class Constructor & destructor of outer class initialize and destroy locks Class name =  “GSP_”  + name of policy A nested class for each policy parameter
Mapping RW[ReadOp, WriteOp] into C++ class  GSP_RW  { public: GSP_RW (); ~GSP_RW (); class ReadOp { public: ReadOp (GSP_RW & data); ~ReadOp (); }; class WriteOp { public: WriteOp (GSP_RW & data); ~WriteOp (); }; }; This policy has two parameters so there are two nested classes
Mapping BoundedProdCons into C++ This is the mapping for BoundedProdCons (int size) [PutOp, GetOp, OtherOp] class  GSP_BoundedProdCons  { public: GSP_BoundedProdCons (int size); ~ GSP_BoundedProdCons (); class  PutOp   {...}; class  GetOp   {...}; class  OtherOp  {...}; }; This policy has three parameters so there are three nested classes The size parameter to the policy maps into a parameter to the constructor of the class
Instantiating GSP_RW[ReadOp, WriteOp] #include “gsp_rw.h” class Foo { private: GSP_RW  m_sync; public: void op1(...) { GSP_RW::ReadOp  scopedLock(m_sync); ... } void op2(...) { GSP_RW::WriteOp  scopedLock(m_sync); ... } }; #include  header file (name of class written in lowercase) Add instance variable whose type is name of policy’s outer class Synchronize an operation by adding a local variable whose type is a nested class of the policy
Instantiating GSP_BoundedProdCons #include “gsp_boundedprodcons.h” class Buffer { private: GSP_BoundedProdCons  m_sync; public: Buffer( int size ) :  m_sync(size)  { ... } void insert(...) { GSP_BoundedProdCons::PutOp  scopedLock(m_sync); ... } void remove(...) { GSP_BoundedProdCons::GetOp  scopedLock(m_sync); ... } }; The  size  parameter of the policy is initialized with value of a parameter to the constructor
4. Critique
Strengths of GSPs Only one person needs to know how to implement GSPs Trivial for everyone else to instantiate GSPs Separates synchronization code from “business logic” code Improve readability and maintainability of both types of code Removes a common source of bugs: Locks are released even if an operation throws an exception Improves portability: API of GSPs does  not  expose OS-specific details of synchronization Efficiency: GSPs can be implemented with inline code
Potential criticisms fo GSPs “ Can they handle  all  my synchronization needs?” 80/20 principle:  most  synchronization needs can be handled by just a small library of GSPs You are not restricted to a library of pre-written GSPs. Instead… You can write new GSPs if the need arises “ GSPs are just a  ScopedMutex  with a new name” The “just” part is inaccurate GSPs generalize the  ScopedMutex  concept so it can be used for a much wider set of synchronization policies
Issues not addressed GSPs do not address: POSIX thread cancellation Timeouts Lock hierarchies In the author’s work, these issues arise infrequently so he did not bother to support them GSPs could probably be extended to support the above issues
5. Ready-to-run GSPs
Ready-to-run GSPs A library of ready-to-use GSPs is available: Download from  www.CiaranMcHale.com/download   Documentation provided in multiple formats: Manual: LaTeX, PDF & HTML Slides: PowerPoint, PDF and N-up PDF Library contains all GSPs discussed in this paper: Mutex[Op] RW[ReadOp, WriteOp] ProdCons[PutOp, GetOp, OtherOp] BoundedProdCons(int size)[PutOp, GetOp, OtherOp] GSPs are implemented for multiple thread packages: POSIX, Solaris, Windows, DCE Dummy (for non-threaded applications)
Using GSP classes Define one of the following preprocessor symbols before you  #include  a GSP header file P_USE_POSIX_THREADS P_USE_SOLARIS_THREADS P_USE_WIN32_THREADS P_USE_DCE_THREADS P_USE_NO_THREADS Typically done with  –D<symbol>  command-line option to compiler
Summary GSPs are a generalization of the  ScopedMutex  class: Out-of-the-box support for mutual-exclusion, readers-writer and (bounded) producer-consumer policies You can write new GSPs if the need arises Benefits: Makes it trivial to add synchronization to a C++ class Makes code easier to read and maintain Portability across multiple thread packages Minimal performance overhead due to  inline  implementation All software and documentation is available: MIT-style license (open-source, non-viral) Download from  www.CiaranMcHale.com/download

More Related Content

PDF
Lab3 testbench tutorial (1)
PDF
Nagios Conference 2013 - BOF Nagios Plugins New Threshold Specification Syntax
ODP
Extending Perl Critic
PDF
Grape generative fuzzing
ODP
YAPC::NA 2007 - An Introduction To Perl Critic
PPT
Refactoring
PDF
Linux Kernel, tested by the Linux-version of PVS-Studio
PPTX
Preprocessor
Lab3 testbench tutorial (1)
Nagios Conference 2013 - BOF Nagios Plugins New Threshold Specification Syntax
Extending Perl Critic
Grape generative fuzzing
YAPC::NA 2007 - An Introduction To Perl Critic
Refactoring
Linux Kernel, tested by the Linux-version of PVS-Studio
Preprocessor

What's hot (13)

PPT
PDF
Classboxes, nested methods, and real private methods
ODP
An Introduction To Perl Critic
PDF
White paper for unit testing using boost
PPT
ATE Pattern Structure Basics
PPT
Unit 4
PDF
Mutation Testing: Start Hunting The Bugs
PDF
Bluespec Tutorial Helloworld
PPTX
System verilog coverage
PDF
Introduction to Clime
PDF
SymfonyCon 2017 php7 performances
PPT
Macros in system programing
PDF
Laporan ai modul 2-if b 2014-14102055-deprilana ego prakasa
Classboxes, nested methods, and real private methods
An Introduction To Perl Critic
White paper for unit testing using boost
ATE Pattern Structure Basics
Unit 4
Mutation Testing: Start Hunting The Bugs
Bluespec Tutorial Helloworld
System verilog coverage
Introduction to Clime
SymfonyCon 2017 php7 performances
Macros in system programing
Laporan ai modul 2-if b 2014-14102055-deprilana ego prakasa
Ad

Similar to Generic Synchronization Policies in C++ (20)

PDF
The Ring programming language version 1.8 book - Part 95 of 202
PDF
Clean code
ODP
Java EE Pattern: Entity Control Boundary Pattern and Java EE
ODP
Developing Drizzle Replication Plugins
PDF
AtoZ about TYPO3 v8 CMS
PPTX
Design Pattern Mastery - Momentum Dev Con 19 Apr 2018
PPTX
Unit 1
DOCX
Srgoc dotnet
PDF
OS_Compilation_Makefile_kt4jerb34834343553
PPTX
A brief overview of java frameworks
PDF
Whoops! Where did my architecture go?
PDF
Data structure scope of variables
PDF
Buffer overflow tutorial
DOCX
Implementing of classical synchronization problem by using semaphores
DOCX
Backtrack Manual Part6
KEY
RL2 Dot Brighton
PPTX
Chapter 2.4
PPT
Software development effort reduction with Co-op
PPTX
Back-2-Basics: .NET Coding Standards For The Real World (2011)
The Ring programming language version 1.8 book - Part 95 of 202
Clean code
Java EE Pattern: Entity Control Boundary Pattern and Java EE
Developing Drizzle Replication Plugins
AtoZ about TYPO3 v8 CMS
Design Pattern Mastery - Momentum Dev Con 19 Apr 2018
Unit 1
Srgoc dotnet
OS_Compilation_Makefile_kt4jerb34834343553
A brief overview of java frameworks
Whoops! Where did my architecture go?
Data structure scope of variables
Buffer overflow tutorial
Implementing of classical synchronization problem by using semaphores
Backtrack Manual Part6
RL2 Dot Brighton
Chapter 2.4
Software development effort reduction with Co-op
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Ad

Recently uploaded (20)

PPTX
Cloud computing and distributed systems.
PDF
KodekX | Application Modernization Development
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
cuic standard and advanced reporting.pdf
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
sap open course for s4hana steps from ECC to s4
PPT
Teaching material agriculture food technology
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Encapsulation theory and applications.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
Cloud computing and distributed systems.
KodekX | Application Modernization Development
Review of recent advances in non-invasive hemoglobin estimation
Chapter 3 Spatial Domain Image Processing.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
cuic standard and advanced reporting.pdf
MYSQL Presentation for SQL database connectivity
Reach Out and Touch Someone: Haptics and Empathic Computing
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Per capita expenditure prediction using model stacking based on satellite ima...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Network Security Unit 5.pdf for BCA BBA.
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
sap open course for s4hana steps from ECC to s4
Teaching material agriculture food technology
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Encapsulation theory and applications.pdf
Unlocking AI with Model Context Protocol (MCP)

Generic Synchronization Policies in C++

  • 1. Generic Synchronization Policies in C++ Ciaran McHale www.CiaranMcHale.com
  • 2. License Copyright (c) 2006 Ciaran McHale Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  • 3. Introduction Most people know that writing synchronization code is: Difficult: APIs are low-level Non-portable: many threading APIs: POSIX, Windows, Solaris, DCE, … In practice, most synchronization code implement a small number of high-level “usage patterns”: Let’s call these generic synchronization policies (GSPs) The most common GSPs can be implemented as a C++ library Using GSPs in applications: Is much easier than using low-level APIs Encapsulates the underlying threading package  provides portability
  • 5. Critical section The following (pseudocode) function uses a critical section: void foo() { getLock(mutex); ... releaseLock(mutex); } The above code is very simple. However… Complexity increases if the function has several exit points: Because releaseLock() must be called at each exit point Examples of extra exit points: Conditional return statements Conditionally throwing an exception
  • 6. Critical section with multiple exit points void foo() { getLock(mutex); ... if (...) { releaseLock(mutex); return; } if (...) { releaseLock(mutex); throw anException; } ... releaseLock(mutex); } Have to call releaseLock() at every exit point from the function
  • 7. Critique Needing to call releaseLock() at every exit point: Clutters up the “business logic” code with synchronization code This clutter makes code harder to read and maintain Forgetting to call releaseLock() at an exit point is a common source of bugs There is a better way…
  • 8. Solution: ScopedMutex class Define a class called, say, ScopedMutex : This class has no operations! Just a constructor and destructor Constructor calls getLock() Destructor calls releaseLock() Declare a ScopedMutex variable local to a function At entry to function  constructor is called  calls getLock() At exit from function  destructor is called  calls releaseLock() The following two slides show: Pseudocode implementation of ScopedMutex class Use of ScopedMutex in a function
  • 9. The ScopedMutex class class ScopedMutex { public: ScopedMutex (Mutex & mutex) : m_mutex(mutex) { getLock(m_mutex); } ~ScopedMutex () { releaseLock(m_mutex); } private: Mutex & m_mutex; };
  • 10. Use of ScopedMutex void foo() { ScopedMutex scopedLock(mutex); ... if (...) { return; } if (...) { throw anException; } ... } No need to call releaseLock() at every exit point from the function!
  • 11. Comments on ScopedMutex This technique is partially well known in the C++ community: 50% of developers the author worked with already knew this technique They considered it to be a “basic” C++ coding idiom Other 50% of developers had not seen the technique before Of the developers who already knew this technique: They all used it for mutex locks Only a few knew it could be used for readers-writer locks too Nobody knew it could be used for almost any type of synchronization code Contribution of this presentation: Generalize the technique so it can be used much more widely To explain how to do this, I need to take a slight detour: Have to introduce the concept of generic synchronization policies
  • 12. 2. The Concept of Generic Synchronization Policies
  • 13. Genericity for types C++ provides template types Example of a template type definition: template<t> class List { ... }; Examples of template type instantiation: List<int> myIntList; List<double> myDoubleList; List<Widget> myWidgetList; Some other languages provide a similar capability, often with different terminology and syntax Perhaps called generic types instead of template types Perhaps surround type parameters with [] instead of <>
  • 14. Genericity for synchronization policies Using a pseudocode notation, here are declarations of mutual exclusion and readers-writer policies Mutex[Op] RW[ReadOp, WriteOp] In above examples, each parameter is a set of operations Example instantiations on operations Op1 , Op2 and Op3 Mutex[{Op1, Op2, Op3}] RW[{Op1, Op2}, {Op3}]
  • 15. Producer-consumer policy Useful when: A buffer is used to transfer data between threads A producer thread puts items into the buffer A consumer thread gets items from the buffer If the buffer is empty when the consumer tries to get an item then the consumer thread blocks The buffer might have other operations that examine the state of the buffer In pseudocode notation, the policy declaration is: ProdCons[PutOp, GetOp, OtherOp] Example instantiations: ProdCons[{insert}, {remove}, {count}] ProdCons[{insert}, {remove}, {}]
  • 16. Bounded producer-consumer policy Variation of the producer-consumer policy: Buffer has a fixed size If the buffer is full when the producer tries to put in an item then the producer thread blocks In pseudocode notation, policy is: BoundedProdCons (int size) [PutOp, GetOp, OtherOp] Typically, the size parameter is instantiated on a parameter to the constructor of the buffer class An example instantiation will be shown later
  • 17. 3. Generic Synchronization Policies in C++
  • 18. Mapping Mutex[Op] into C++ class GSP_Mutex { public: GSP_Mutex () { /* initialize m_mutex */ } ~GSP_Mutex () { /* destroy m_mutex */ } class Op { public: Op (GSP_Mutex & data) : m_data(data) { getLock(m_data.m_mutex); } ~Op () { releaseLock(m_data.m_mutex); } private: GSP_Mutex & m_data; }; private: friend class ::GSP_Mutex::Op; OS-specific-type m_mutex; }; Constructor & destructor of nested class get and release locks stored in the outer class Constructor & destructor of outer class initialize and destroy locks Class name = “GSP_” + name of policy A nested class for each policy parameter
  • 19. Mapping RW[ReadOp, WriteOp] into C++ class GSP_RW { public: GSP_RW (); ~GSP_RW (); class ReadOp { public: ReadOp (GSP_RW & data); ~ReadOp (); }; class WriteOp { public: WriteOp (GSP_RW & data); ~WriteOp (); }; }; This policy has two parameters so there are two nested classes
  • 20. Mapping BoundedProdCons into C++ This is the mapping for BoundedProdCons (int size) [PutOp, GetOp, OtherOp] class GSP_BoundedProdCons { public: GSP_BoundedProdCons (int size); ~ GSP_BoundedProdCons (); class PutOp {...}; class GetOp {...}; class OtherOp {...}; }; This policy has three parameters so there are three nested classes The size parameter to the policy maps into a parameter to the constructor of the class
  • 21. Instantiating GSP_RW[ReadOp, WriteOp] #include “gsp_rw.h” class Foo { private: GSP_RW m_sync; public: void op1(...) { GSP_RW::ReadOp scopedLock(m_sync); ... } void op2(...) { GSP_RW::WriteOp scopedLock(m_sync); ... } }; #include header file (name of class written in lowercase) Add instance variable whose type is name of policy’s outer class Synchronize an operation by adding a local variable whose type is a nested class of the policy
  • 22. Instantiating GSP_BoundedProdCons #include “gsp_boundedprodcons.h” class Buffer { private: GSP_BoundedProdCons m_sync; public: Buffer( int size ) : m_sync(size) { ... } void insert(...) { GSP_BoundedProdCons::PutOp scopedLock(m_sync); ... } void remove(...) { GSP_BoundedProdCons::GetOp scopedLock(m_sync); ... } }; The size parameter of the policy is initialized with value of a parameter to the constructor
  • 24. Strengths of GSPs Only one person needs to know how to implement GSPs Trivial for everyone else to instantiate GSPs Separates synchronization code from “business logic” code Improve readability and maintainability of both types of code Removes a common source of bugs: Locks are released even if an operation throws an exception Improves portability: API of GSPs does not expose OS-specific details of synchronization Efficiency: GSPs can be implemented with inline code
  • 25. Potential criticisms fo GSPs “ Can they handle all my synchronization needs?” 80/20 principle: most synchronization needs can be handled by just a small library of GSPs You are not restricted to a library of pre-written GSPs. Instead… You can write new GSPs if the need arises “ GSPs are just a ScopedMutex with a new name” The “just” part is inaccurate GSPs generalize the ScopedMutex concept so it can be used for a much wider set of synchronization policies
  • 26. Issues not addressed GSPs do not address: POSIX thread cancellation Timeouts Lock hierarchies In the author’s work, these issues arise infrequently so he did not bother to support them GSPs could probably be extended to support the above issues
  • 28. Ready-to-run GSPs A library of ready-to-use GSPs is available: Download from www.CiaranMcHale.com/download Documentation provided in multiple formats: Manual: LaTeX, PDF & HTML Slides: PowerPoint, PDF and N-up PDF Library contains all GSPs discussed in this paper: Mutex[Op] RW[ReadOp, WriteOp] ProdCons[PutOp, GetOp, OtherOp] BoundedProdCons(int size)[PutOp, GetOp, OtherOp] GSPs are implemented for multiple thread packages: POSIX, Solaris, Windows, DCE Dummy (for non-threaded applications)
  • 29. Using GSP classes Define one of the following preprocessor symbols before you #include a GSP header file P_USE_POSIX_THREADS P_USE_SOLARIS_THREADS P_USE_WIN32_THREADS P_USE_DCE_THREADS P_USE_NO_THREADS Typically done with –D<symbol> command-line option to compiler
  • 30. Summary GSPs are a generalization of the ScopedMutex class: Out-of-the-box support for mutual-exclusion, readers-writer and (bounded) producer-consumer policies You can write new GSPs if the need arises Benefits: Makes it trivial to add synchronization to a C++ class Makes code easier to read and maintain Portability across multiple thread packages Minimal performance overhead due to inline implementation All software and documentation is available: MIT-style license (open-source, non-viral) Download from www.CiaranMcHale.com/download