By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,194 Members | 888 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,194 IT Pros & Developers. It's quick & easy.

C or C++ program?

P: n/a
I need some advice regarding a coding requirement that may suggest the
need for an object oriented solution. The code fragments presented
here attempt to solve the problem in C.

The problem:

Data Packets are received from a socket and consist of 3 elements: the
Packet Type, the "Item", and some Data.

The Packet type represents either:

(1) A Task to be performed on the Item using the supplied Data
(2) A Condition that has arisen for the Item
(3) A signal to exit

A Task triggers a function that executes code based on the Packet's
Item and Data. Often the Task will trigger, and must wait for,
additional Packets to satisfy certain Conditions before the Task can
complete. The number of Conditions and the length of time spent
waiting will vary for each Task. In this example, there is a "simple"
Task that waits for one condition and a "complex" Task that waits for
2 conditions at different points of processing. In the actual
implementation, there would be many more Tasks, some with 3 or more
Conditions.

Listing 1 represents what I know will not work but illustrates the
problem. Listing 2 represents the best way I've come up with to handle
this in C.

Is Listing 2 a sound approach?
Is there a better way in C?
Would it be much easier in C++ or another "object oriented" language?

Thanks a million!

-Kerry
----------
Listing 1:
----------

As Packets are received, the appropriate function is called for
processing. During processing, additional Packets are received from
within the functions so that the Task can wait for the appropriate
condition(s) and Data before continuing the Task.

A fundamental problem with this approach is that while a function is
waiting for additional Packets to indicate the desired Condition, a
Packet may arrive for some other Item. Handling the new Packet within
the function seems impossible - what if the desired Condition for the
first Packet arrives during the processing of the second?

I could store incoming Packets that I'm not ready for and process them
after the pending Task has completed but that could lead to
"deadlocks" if the new Packet was meant to supercede the first. At
best, the new Tasks would be unnecessarily delayed since they'd have
to wait for the pending Task's Conditions to be met.

// Define Packet Structure

struct stx
{ int ptype;
int item;
int data;
};

// Define Packet Types

int DoSimpleTask = 0;
int DoComplexTask = 1;
int DoOtherTask = 2;
int ConditionA = 3;
int ConditionB = 4;
int ConditionC = 5;
int DoExit = 6;

struct stx x;

..
..
..
do
{
x = BlockForNextPacket();

switch (x.ptype)
{
DoSimpleTask: rc = funcDoSimpleTask(x.item, x.data);
break;

DoComplexTask: rc = funcDoComplexTask(x.item, x.data);
break;

DoOtherTask: rc = funcDoOtherTask(x.item, x.data);
break;

DoExit: rc = funcExit();
break;

default: break;
}
}
while (x.ptype != DoExit)
..
..
..

int funcDoSimpleTask(int i, int d)
{
// Perform Task here

// Wait until Condition A for this item exists
do
{ x = BlockForNextPacket(); }
while ( (x.item != i) || (x.ptype != ConditionA) )

// Perform post-Task processing here

return 0;
}

int funcDoComplexTask(int i, int d)
{
struct stx x;

// Perform 1st part of Task here

// Wait until Condition A for this Item exists
do
{ x = BlockForNextPacket(); }
while ( (x.item != i) || (x.ptype != ConditionA) )

// Perform 2nd part of Task here

// Wait until Condition B for this Item exists
do
{ x = BlockForNextPacket(); }
while ( (x.item != i) || (x.ptype != ConditionB) )

// Perform post-Task processing here

return 0;
}

int funcDoOtherTask(int i, int d)
{
// Perform complete Task here and exit immediately

return 0;
}


----------
Listing 2:
----------

All Packets are received within a single loop. Tasks have been broken
up into fragments so that none of them require fetching additional
Packets. Since certain Packets (Condition A for instance) can mean
different things at different times, an array has been added to
maintain the State of incomplete Tasks. While all Tasks are handled
correctly, the overhead needed to maintain State is confusing, even in
this simplistic example.

Although it's not handled here for the sake of brievity, if a new Task
arrives for an Item that is already in a pending State, either the new
or old Task would need to be aborted. Identifying and handling these
situations seems possible since the State arrays are in scope when the
new Task arrives.

..
..
..

int SimpleTaskState[number-of-items];
int ComplexTaskState[number-of-items];

do
{
x = BlockForNextPacket();

switch (x.ptype)
{
DoSimpleTask: { rc = funcDoSimpleTask(x.item, x.data);
// Update State - waiting for Cond A
SimpleTaskState[x.item] = 1;
break;
}

DoComplexTask: { rc = funcDoComplexTask(x.item, x.data);
// Update State - waiting for Cond A
ComplexTaskState[x.item] = 1;
break;
}

DoOtherTask: { rc = funcDoOtherTask(x.item, x.data);
break;
}

DoExit: { rc = funcExit();
break;
}

ConditionA: { if ( SimpleTaskState[x.item] == 1 )
{ // Simple Task was waiting for Cond A
// Now finish the Task
rc = funcDoSimplePost(x.item, x.data);
// Task complete, reset State
SimpleTaskState[x.item] = 0;
}
else if ( ComplexTaskState[x.item] == 1 )
{ // Complex Task was waiting for Cond A
// Now do part 2 of Task
rc = funcDoComplexPart2(x.item, x.data);
// Part 2 complete, now waiting for Cond B
ComplexTaskState[x.item] = 2;
}
else
{ // Condition A is irrelevant right now
}
break;
}

ConditionB: { if ( ComplexTaskState[x.item] == 2 )
{ // Complex Task was waiting for Cond B
rc = funcDoComplexPost(x.item, x.data);
// Task complete, reset state
ComplexTaskState[x.item] = 0;
}
else
{ // Condition B is irrelevant right now
}
break;
}

default: break;
}
}
while (x.ptype != DoExit)
..
..
..

int funcDoSimpleTask(int i, int j)
{
// Perform Task here
return 0;
}

int funcDoSimplePost(int i, int j)
{
// Perform post-Task processing here
return 0;
}

int funcDoComplexTask(int i, int j)
{
// Perform 1st part of Task here
return 0;
}

int funcDoComplexPart2(int i, int j)
{
// Perform 2nd part of Task here
return 0;
}

int funcDoComplexPost(int i, int j)
{
// Perform post-Task processing here
return 0;
}

int funcDoOtherTask(int i, int j)
{
// Perform complete Task here and exit immediately

return 0;
}
Nov 13 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Below is a sample of data that would be supplied to my program. The
sequence and packet columns are added for clarity - the algorithm as
written doesn't need these values for anything. Since the data has no
effect on the routing of packets, I made them all 0 for the example.
Seq packet ptype item data

1 1 simple 1 0
2 a 1 0

2 3 complex 1 0
4 a 1 0
5 b 1 0

3 6 simple 1 0
7 complex 2 0
8 a 1 0
9 a 2 0
10 b 2 0

4 11 complex 1 0
12 complex 2 0
13 a 2 0
14 a 1 0
15 b 1 0
16 simple 1 0
17 b 2 0
18 a 1 0

5 19 complex 1 0
20 b 1 0
21 a 1 0
22 b 1 0
In the first sequence of Packets, a Simple Task is initiated for Item
1 immediatedly followed by Condition A for Item 1 and the Task
completes.

In the second sequence, a Complex Task is initiated for Item 1
immediately followed by Condition A then Condition B and the Task
completes. When Packet 4 arrives, the State of Item 1 is examined to
determine which routine to call since "Condition A" can mean "complete
simple task" or "proceed with complex task" depending on the State.

In the third sequence, a Simple Task is initiated for Item 1 followed
by a Complex Task initiation for Item 2 before Item 1's Task has
completed. The State of each Item is maintained as "waiting for
condition a". When Packet 8 arrvies, Item 1's Simple Task completes.
Packets 9 and 10 provide the conditions for Item 2's Complex Task to
complete.

In the forth sequence, Item 2's first condition is satisfied before
Item 1's however the next 2 Packets allow Item 1's Task to complete
before Item 2. Before Item 2 receives it's final Condition in Packet
17, Item 1 has a new Task begun in Packet 16.

In the final sequence, Condition B arrives before Condition A. The
Condition is ignored as it's meaningless in the Item's current state.
When it arrives again as the last Packet, the Task completes.
Nov 13 '05 #2

P: n/a
Kerry wrote:
I need some advice regarding a coding requirement that may suggest the
need for an object oriented solution. The code fragments presented
here attempt to solve the problem in C. [snip]

Is Listing 2 a sound approach?
Is there a better way in C?
Would it be much easier in C++ or another "object oriented" language?

Thanks a million!

-Kerry

[snip -- long listings of code]

The term "better" is a vague term.
What is your explanation of "better"?
Do you want your code optimized for speed?
Do you want your code optimized for space?
Do you want code that is more readable?
Is code that can be developed faster with
good quality better?
Does your code work correctly?
Does your code handle all user possiblities
without crashing?
Can portions of your code be reused without
modification?

If the code is for a business, then I suggest you
hold a code review with your peers. If your code
works correctly, then move on to other parts of
the project. Don't optimize working code, unless
absolutely necessary. Most of a program's development
cost is your time. The more time you waste performing
unneeded optimizations, the more the program will
cost and the delivery date will be postponed.

If your programm has duplicate code fragments, but
it works correctly, then you are done. After you are
finished have the time (or can paid for the extra time)
then go ahead and optimize it. Just remember, once a
working program is modified in any manner, it must be
retested all over again, a.k.a. regression testing.

My hobby project has never been released in 20 years
because I keep optimizing, redesigning and starting
over. But then, I am using it as a learning tool.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
http://www.sgi.com/tech/stl -- Standard Template Library

Nov 13 '05 #3

P: n/a
> The term "better" is a vague term.
What is your explanation of "better"?


Readabilty may best describe what I dislike about my solution. The
1st listing was more readable in that there was a specific routine to
handle each task. One could examine the code for a routine and easily
determine what conditions need to be satisfied (and in what order) for
the task to complete. But it doesn't allow for multiple incomplete
tasks to co-exist, hence listing 2.

I was hoping that someone would see what I'm trying to accomplish and
say "Oh, that's a classic example of (some common scenerio) which is
most often handled with (some known algorithm)". The problem I've
described doesn't seem terribly unique - just unique in MY experience.
Thanks for the advice, Thomas.

-Kerry
Nov 13 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.