Multicore Programming (Multiprocessing) Visual C++ Tips: member function execution flow
Hey all,
Long time no read... Well, I've been very busy. I thought that I'd start with a technical post (maybe cause there is nothing that exciting with my life, and maybe because I pretend that this is the case :)
As you all know I have beed busy in the are of parallel computing, what people call multi-core programming.
I have learned that Object Oriented programming is very problematic with parallel systems and that OO helps us at design time but has almost no benifit for run-time and many times even damages our ability to understand execution flow. See my post on my Intel blog here: http://softwareblogs.intel.com/2008/08/22/flaws-of-object-oriented-modeling/
It is very clear to me that people are used to OOP and will still be using it for many years to come so I have compiled a few basic guidelines for OO Programming to help us get the best of both worlds: manageable code, and clear execution flow. Here is the first:
Prefer clear execution flow for member function
The execution flow is the most important aspect in a parallel application. When the source code that has a clear and simple flow the application is simple to debug and the code is easy to follow. Once of the greatest problems of OOD is multiple short functions that call each other. Code review is almost meaningless and it is extremely difficult to follow the execution flow using a debugger or by going over the execution logs.
It would thus mean a great improvement in code usability when few long functions are used. Sometimes it is easier to read a function of five lines that looks like this:
void SampleFunction()
{
int ch = ReadByte();
if ( TestValue( ch ) )
{
Logger.WriteLine( "OK" );
}
else
{
throw ( "Error" );
}
}
The code above is simple to read and is very clean, however there is a problem with this code. It is hard to tell if any of these functions are blocking, using locks, throw any exceptions, and worse than all usually an application that uses such functions will have many such short functions. Here is a possible execution flow for such an application:
- SampleFunction
- ReadByte
- TestFileOpen
- GetInputFileHandle
- ReadCharFromFile
- TestValue
- GetHashFromInt
- FindHash
The same function could be implemented in the following illustrative way:
void SampleFunction()
{
bool ok = false;
HFILE hFile = GetInputFileHandle();
if ( hFile > 0 )
{
int ch = fgetchar(hFile);
if ( ch > EOF )
{
ch = (ch * 0x123 + 57 ) / 33; // get HASH
if ( lpHashTable[ ch ] != NULL )
{
ok = true;
}
}
}
if (ok)
{
Logger.WriteLine( "OK" );
}
else
{
throw ( "Error" );
}
}
This may be a longer function and it is not "pure" object oriented programming but now you can read and code and understand what it does. You can also find bugs in the execution flow by a means of a simple code review and if you try to debug it step by step you can understand where you are in the flow of the code.
Coding this way helps in finding idiotic deadlocks and reduces the number of exceptions thrown between functions, which also helps in keeping a clear execution flow.
Your opinion is most welcome.
Asaf