Suggestions needed for my Process Management Code

Mar 23, 2011 at 6:59pm
Hi. I'm writing code for process lists (executes every 'process' each 'frame') and process stacks (executes the top 'process' each 'frame'). The question I have regards the nature of the processes themselves (note that despite what the name may or may not suggest, I am not writing multithreaded code just yet).

Basically, each process must have its own private data, initialization code, shutdown code, and 'per frame' code. This seemed at first sight to be an optimal opportunity to use object oriented technique.

Originally, I thought I would define a process like this:
1
2
3
4
class Process {
public:
   virtual void Execute(boost::any& data = 0) = 0;
};
.

The user would then inherit the class for each process. However, this would mean that every process on the list/in the stack (they are all different) would need its own class and furthermore, the user would have to instantiate an instance of each process before pushing it onto the stack.

EDIT: This way, initialization could be put in the constructor, shutdown in the destructor and data would be in the form of private member variables.

So each class will only ever have one instance and every process must be a separate class. This seemed to me to end up too messy, so instead I decided to do the processes as function pointers alone, expecting a function something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void some_function(Purpose purpose, boost::any& data = 0) // Purpose is enum
{
   // private data as static variables:
   static int foo;
   char* bar; // only using this over std::string to facilitate the example

   // initialization
   if (Purpose == Init)
   {
       foo = 1;
       bar = new char[4];
       strcpy(bar, "etc");
   }

   // loop
   if (Purpose == Execute)
   {
      foo++;
      std::cout << foo << ' ' << bar << std::endl;
   }

   // shutdown
   if (Purpose = Shutdown)
   {
      delete [] name;
   }
}


This is functional, but it seems a very inelegant way of doing it. Can anyone suggest how to use classes for processes without a different data type for every process, or indeed just a way to improve the second method?

Thanks in advance for any help.
Last edited on Mar 23, 2011 at 7:00pm
Mar 24, 2011 at 12:05am
You could put your process class into a vector. Then add or take away from it as needed.

http://cplusplus.com/reference/stl/vector/

(A vector is pretty much a dynamic array with lots of functionality)
Mar 24, 2011 at 1:03am
I am not writing multithreaded code just yet


=] Why not?

I'm not sure what the purpose of your code is, however it reminds me of a thread pool:
http://en.wikipedia.org/wiki/Thread_pool_pattern <- yay wiki

I can kind of see what you're doing here. Can you let me in on the secret? What are you trying to do?
(you don't have to share, but I may possibly be able to help you out if I knew a little more)
Mar 24, 2011 at 7:40am
@ModShop Thanks for idea. That is in fact what I have done - I should really have posted all the source code from the start!

@Ultifinitus Once I make the code work on a single thread, I intend to use SFML threads for multithreading. I have no problem sharing the code as it will go on my blog eventually anyway.
(I didn't share it before because I thought it would be irrelevant and waste space...)

So there are three header files (right now, all functions are inline, but bear in mind that I shall be putting them into .cpp files once everything is working).

Basically, I am writing a game engine and I got the idea for these two classes from some old book on game development. The process stack is theoretically useful for this:
[pseudocode]
push(menu screen)
when (user starts game) push(game main)
when (user opens inventory) push(inventory)
when (user closes inventory) pop() // remove inventory and return to game main
when (user quits to menu) pop() // remove main game and return to menu
when (user quits) pop() // remove menu and quit
[/pseudocode]

As for the process list, perhaps I would use it for something like concurrently running Rendering, Physics, Audio and Logic. Basically, I am not sure how much I'll use to process list, but once I have designed the process itself, adding the process list was not much extra effort.

Here's all the relevant code. The function I wrote above could then be added to the list or pushed onto the stack.

If something's still unclear just ask :) And sorry it's so long...

EDIT: You'll see where I've commented out multithreaded code. The reason I haven't implemented it yet is that I needed to come up with an algorithm to choose which thread to add each process to and I wanted to sort the basic classes before I think about that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/************************ PROCESS.HPP - General Stuff ************************/
#pragma once
#ifndef _ASCENDANTENGINE_PROCESS_HPP
#define _ASCENDANTENGINE_PROCESS_HPP

#include <vector>
#include <boost/any.hpp>

namespace AscendantEngine {

	/// Calling purpose for process
	enum CallingPurpose { Purpose_Init, Purpose_Loop, Purpose_Shutdown };

	/// Definition of Process type
	typedef void (*Process)(boost::any, CallingPurpose);

	/// A list of arbitrary data
	typedef std::vector<boost::any> Datalist;

}

#endif



/*********************** PROCESSLIST.HPP *****************************/
#pragma once
#ifndef _ASCENDANTENGINE_PROCESSLIST_HPP
#define _ASCENDANTENGINE_PROCESSLIST_HPP

#include <vector>
#include <map>
#include <string>
#include <utility>
#include <SFML/System.hpp>
#include <boost/any.hpp>

#include "Process.hpp"

namespace AscendantEngine {

	/// The process list class
	class ProcessList {
		//class thread : public sf::Thread {
		//	std::vector<Process> processes;

		//	void Run(void* data) { for (int i=0; i<processes.size(); i++) processes[i](
		//}

		int nThreads; // number of threads: not yet implemented
		std::map<std::string, Process> processes;
		//std::vector<sf::Thread> threads;

		void _execute(std::vector<boost::any>* data = 0)
		{
			unsigned datItr = 0;
			std::map<std::string, Process>::iterator procItr = processes.begin();
			for (; procItr != processes.end(); datItr++, procItr++)
				if (data && datItr < data->size())
					procItr->second(data[datItr], Purpose_Loop);
				else
					procItr->second(0, Purpose_Loop);
		}

		void _remove_all(Datalist* data = 0)
		{
			unsigned datItr = 0;
			std::map<std::string, Process>::iterator procItr = processes.begin();
			for (; procItr!=processes.end(); procItr++, datItr++)
				if (data && datItr < data->size())
					procItr->second(data[datItr], Purpose_Shutdown);
				else
					procItr->second(0, Purpose_Shutdown);
			processes.clear();
		}

	public:
		ProcessList()
		{
			
		}
		~ProcessList() { RemoveAll(); }

		void Add(Process process, std::string ID, /*unsigned threadNumber = 0,*/ boost::any data = 0)
		{
			if (process == 0) return;
			processes.insert(std::pair<std::string, Process>(ID, process));
			process(data, Purpose_Init);
			// TODO: threading
		}
		void Push(Process process, std::string ID, /*unsigned threadNumber = 0,*/ boost::any data = 0) { Add(process, ID, /*threadNumber,*/ data); }

		void Remove(std::string ID, boost::any data = 0)
		{
			if (processes.find(ID) != processes.end())
				processes.find(ID)->second(data, Purpose_Shutdown);
			processes.erase(ID);
		}
		void Pop(std::string ID, boost::any data = 0) { Remove(ID, data); }
		void RemoveAll()
		{
			_remove_all();
		}
		void RemoveAll(Datalist data)
		{
			_remove_all(&data);
		}
		void PopAll() { RemoveAll(); }
		void PopAll(Datalist data) { RemoveAll(data); }

		void Execute()
		{
			_execute();
		}
		void Execute(Datalist data)
		{
			_execute(&data);
		}
	};

}

#endif


/***************************** PROCESS STACK ***************************/
#pragma once
#ifndef _ASCENDANTENGINE_PROCESSSTACK_HPP
#define _ASCENDANTENGINE_PROCESSSTACK_HPP

#include <stack>
#include <vector>
#include <boost/any.hpp>
#include "Process.hpp"

namespace AscendantEngine {

	class ProcessStack {
		std::stack<Process> processes;

		void _pop_all(Datalist* data = 0)
		{
			unsigned dataItr = 0;
			while (Pop((data&&(dataItr < data->size()))?(*data)[dataItr]:0))
				;
		}

	public:
		~ProcessStack() { PopAll(); }

		void Push(Process process, boost::any data = 0)
		{
			if (process == 0) return;
			process(data, Purpose_Init);
			processes.push(process);
		}
		void Add(Process process, boost::any data = 0) { Push(process, data); }

		bool Pop(boost::any data = 0)
		{
			if (processes.empty()) return false;
			processes.top()(data, Purpose_Shutdown);
			processes.pop();
			if (processes.empty()) return false; else return true;
		}
		bool Remove(boost::any data = 0) { return Pop(data); }
		void PopAll() { _pop_all(); }
		void PopAll(Datalist data) { _pop_all(&data); }
		void RemoveAll() { PopAll(); }
		void RemoveAll(Datalist data) { PopAll(data); }

		void Execute(boost::any data = 0)
		{
			processes.top()(data, Purpose_Loop);
		}
	};

}

#endif 
Last edited on Mar 24, 2011 at 5:07pm
Topic archived. No new replies allowed.