Factory method -- best practices for portability

E

Ed Fair

Hi,

I'm a long-time C programmer, I've started making the transition to "real
C++" recently. I am puzzled about how to write a factory method. Any
suggestions, pointers or references to documentation would be appreciated.

Here is some background information about what I'm doing: I have written a
large body of code that makes extensive use of mutexes. Most of my code is
portable, except for the mutexes, which are platform specific. I've
abstracted the notion of mutex with an abstract class "mutex", with pure
virtual functions get() and release() to obtain and release the mutex,
respectively. The large body of code uses pointers to these mutexes.

I am deriving "implementation classes" from mutex, for example win32Mutex,
linuxMutex, and posixMutex, on a per-platform basis and implementing get()
and release() accordingly.

Everything seems to be working OK with my simple tests, but I want to use a
"factory method" to cleanly produce (pointers to) mutexes. I can't grok how
to do this at a high-level, and I can't quite "seal off" the
platform-specific code from the large body of platform-independent code.

The idea is that I want to minimize platform-specific things in the large
body of code by calling a factory method when a mutex is needed, as opposed
to calling the (platform specific) constructors in the implementation
classes directly.

Should I:
1) Try to make the factory method a static member function of class mutex?
2) Create another class mutexMaker with member function makeNewMutex(), and
derive classes like win32MutexMaker and linuxMutexMaker from it?
3) Write a non-member function?
4) Use #IFDEF and #INCLUDE and #3 above?
5) Something else that I haven't thought of?

Thanks in advance for any insight.

ed
 
D

David Fisher

Ed Fair said:
I am deriving "implementation classes" from mutex, for example win32Mutex,
linuxMutex, and posixMutex, on a per-platform basis and implementing get()
and release() accordingly.

Everything seems to be working OK with my simple tests, but I want to use a
"factory method" to cleanly produce (pointers to) mutexes. I can't grok how
to do this at a high-level, and I can't quite "seal off" the
platform-specific code from the large body of platform-independent code. ....
Should I:
1) Try to make the factory method a static member function of class mutex?
2) Create another class mutexMaker with member function makeNewMutex(), and
derive classes like win32MutexMaker and linuxMutexMaker from it?
3) Write a non-member function?
4) Use #IFDEF and #INCLUDE and #3 above?
5) Something else that I haven't thought of?

Here are some appropriate "design patterns" for this problem:

Abstract Factory (#2 above) -
http://home.earthlink.net/~huston2/dp/factory.html

- particularly used for "families" of class objects, eg. win32Mutex,
win32Socket, linuxMutex, linuxSocket ...

Factory Method - http://home.earthlink.net/~huston2/dp/factoryMethod.html

- add a virtual newMutex() function to class Mutex, and derive win32Mutex,
linuxMutex etc. from Mutex.

Prototype - http://home.earthlink.net/~huston2/dp/prototype.html

- copy a prototypical example of a mutex (which is created at the beginning
of the program) whenever a new one is needed.


David F
 
D

Daniel T.

Ed Fair said:
I'm a long-time C programmer, I've started making the transition to "real
C++" recently. I am puzzled about how to write a factory method. Any
suggestions, pointers or references to documentation would be appreciated.

Here is some background information about what I'm doing: I have written a
large body of code that makes extensive use of mutexes. Most of my code is
portable, except for the mutexes, which are platform specific. I've
abstracted the notion of mutex with an abstract class "mutex", with pure
virtual functions get() and release() to obtain and release the mutex,
respectively. The large body of code uses pointers to these mutexes.

I am deriving "implementation classes" from mutex, for example win32Mutex,
linuxMutex, and posixMutex, on a per-platform basis and implementing get()
and release() accordingly.

Everything seems to be working OK with my simple tests, but I want to use a
"factory method" to cleanly produce (pointers to) mutexes. I can't grok how
to do this at a high-level, and I can't quite "seal off" the
platform-specific code from the large body of platform-independent code.

The idea is that I want to minimize platform-specific things in the large
body of code by calling a factory method when a mutex is needed, as opposed
to calling the (platform specific) constructors in the implementation
classes directly.

Should I:
1) Try to make the factory method a static member function of class mutex?
2) Create another class mutexMaker with member function makeNewMutex(), and
derive classes like win32MutexMaker and linuxMutexMaker from it?
3) Write a non-member function?
4) Use #IFDEF and #INCLUDE and #3 above?
5) Something else that I haven't thought of?

Your trying too hard Ed. :) Factory methods are good for runtime
polymorphism, but you don't have any of that in this case. The linux
program will always use linux mutexes for example. You simply need to
create H and CPP files for each mutex type, but give them all the same
interface and class name, then link in the one you want for the version
you are compiling.
 
E

Ed Fair

Thanks, David, these made for good reading.

ed

David Fisher said:
use

Here are some appropriate "design patterns" for this problem:

Abstract Factory (#2 above) -
http://home.earthlink.net/~huston2/dp/factory.html

- particularly used for "families" of class objects, eg. win32Mutex,
win32Socket, linuxMutex, linuxSocket ...

Factory Method - http://home.earthlink.net/~huston2/dp/factoryMethod.html

- add a virtual newMutex() function to class Mutex, and derive win32Mutex,
linuxMutex etc. from Mutex.

Prototype - http://home.earthlink.net/~huston2/dp/prototype.html

- copy a prototypical example of a mutex (which is created at the beginning
of the program) whenever a new one is needed.


David F
 
E

Ed Fair

Thanks, Daniel.

ed

Daniel T. said:
Your trying too hard Ed. :) Factory methods are good for runtime
polymorphism, but you don't have any of that in this case. The linux
program will always use linux mutexes for example. You simply need to
create H and CPP files for each mutex type, but give them all the same
interface and class name, then link in the one you want for the version
you are compiling.
 
N

Nick Hounsome

Ed Fair said:
Hi,

I'm a long-time C programmer, I've started making the transition to "real
C++" recently. I am puzzled about how to write a factory method. Any
suggestions, pointers or references to documentation would be appreciated.

Here is some background information about what I'm doing: I have written a
large body of code that makes extensive use of mutexes. Most of my code is
portable, except for the mutexes, which are platform specific. I've
abstracted the notion of mutex with an abstract class "mutex", with pure
virtual functions get() and release() to obtain and release the mutex,
respectively. The large body of code uses pointers to these mutexes.

This will significantly slow your code compared to native mutex calls which
are often just macros with
no function call at all if there is no contention.

One responder suggested just linking to different versions which is fine but
still not very efficient.

To get maximum speed the answer is templates
- parameterize everything with a class required to contain all the types and
methods that you need. Default this parameter to ThreadUtil or some such.
- Have a Thread.h header that conditionally includes the appropriate system
header, your platform specific thread class header and which typedefs the
platform specfic classes to ThreadUtil
- Make all the methods of your classes inline

e.g.

PosixThreadUtil.h

#include <pthread.h>
struct PosixThreadUtil
{
struct Mutex
{
pthread_mutex_t m_mutex;
void lock() { pthread_mutex_lock(&m_mutex); }
//etc
};
// threads, condvars etc
};

ThreadUtil.h

#ifdef POSIX_SOURCE
#include "PosixThreadUtil.h"
typedef PosixThreadUtil ThreadUtil;
#elif defined(WIN32)
#include "WindowsThreadUtil.h"
typedef WindowsThreadUtil ThreadUtil;
#else
#error no thread class available
#endif

stuff.cpp

#include "ThreadUtil.h"

template <class THREAD=ThreadUtil>
void unrealistic()
{
typename ThreadUtill::Mutex mutex;
mutex.lock(); // should be inlined to pthread_mutexlock for POSIX
}

This mechanism works and is efficient but be warned - different systems
model threads and their control very differently - mutex/critical section is
easy but there is apparently no simple equivalent to pthread cond in
Windows.
There is a book (sorry - I can't remember the title) that spends several
hundred pages developing an interface that can be implemented reasonably in
both windows and posix

P.S. A good use for the library substitution approach is where your code is
supposed to be thread safe but doesn't actually use threads itself (it is
obviously part of a library) - In this case you can provide a dummy for
applications that don't actually use threads. Alternatively you could use
the templates and have a dummy and have no overhead - it depends on whether
you are delivering source or a library.

I think DEC used to use library substitution for single/multi threaded apps.
 
E

Ed Fair

Nick,
This will significantly slow your code compared to native mutex calls which
are often just macros with
no function call at all if there is no contention.

Are you saying that the overhead of the virtual member function call will
add significant overhead? Presumably the implementation member function
will contain such a native mutex call...
One responder suggested just linking to different versions which is fine but
still not very efficient.

Because it still contains the above overhead? I've about ruled out this
approach, because it taints the abstraction with implementation details.
To get maximum speed the answer is templates
- parameterize everything with a class required to contain all the types and
methods that you need. Default this parameter to ThreadUtil or some such.
- Have a Thread.h header that conditionally includes the appropriate system
header, your platform specific thread class header and which typedefs the
platform specfic classes to ThreadUtil
- Make all the methods of your classes inline

I originally started to use templates, but after consulting the Mozilla
"Portability Guide" I decided to avoid templates and inline functions -- do
you have any comments about this, or other comments on "extreme
portability"?
This mechanism works and is efficient but be warned - different systems
model threads and their control very differently - mutex/critical section is
easy but there is apparently no simple equivalent to pthread cond in
Windows.

I'm just after mutex/critical section, that's all.
 
N

Nick Hounsome

Ed Fair said:
Nick,


Are you saying that the overhead of the virtual member function call will
add significant overhead? Presumably the implementation member function
will contain such a native mutex call...

Whether the overhead is significant can only really depend on your app but
since a lot of people use threads because they
want to be as fast as possible the overhead may be significant - it all
depend on the app and the granularity of the locking.

The implementation of lock and unlock may not invoke a function call at all
(I'm not guessing - I've looked at some headers).
The lock call only needs to make a call if the lock is already owned. The
unlock call only needs to make a call if something another thread is
waiting.
Because it still contains the above overhead? I've about ruled out this
approach, because it taints the abstraction with implementation details.

I don't see how. It makes for a messy build but the abstraction is still
clean.
I originally started to use templates, but after consulting the Mozilla
"Portability Guide" I decided to avoid templates and inline functions -- do
you have any comments about this, or other comments on "extreme
portability"?

I cannot think of any reason to avoid these - were not talking anything
exotic here - no partial specializations - no defaults.

I don't know of any reason at all not to use inline functions. Code bloat is
a possibility but that isn't a portability issue.
section

I'm just after mutex/critical section, that's all.

So you are creating a thread safe library of some sort?
 
E

Ed Fair

Nick,
So you are creating a thread safe library of some sort?

Yes, it is a small static library I'm creating, for use within my
multi-threaded application only. I will apply what I learn here to a few
other static libraries that abstract other platform specific things (such as
logFile, tapeDrive, etc).

I'm maximizing my dogma here (and showing my ignorance too) because I'm "in
my first rewrite", having learned the hard way how *not* to write portable
code; my stated goal for the next version is platform independence and ease
of portability. That's why I'm trying so hard to minimize the source code
changes required upon each port. I have many source files that make up
this project, the biggest ones are becoming "platform independent", meaning
that they will not need to be "rewritten" for each port. However, they will
still at least need some tweaking... I'm guessing at least the factory
classes will have to be changed at each port, and some different includes
will be required at the top of each source file that is "platform
independent".

I've looked pretty hard for insight into this, without luck; including the
GNU Goat Book.

ed
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top