[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
JCSP Assistance ?
Folks,
I am writing some software in Microsoft VS 2005 using C# and VB, and one of
the design requirements is that it's multithreaded. I know that the
Microsoft threading model is rather awkward to use, so thought of JCSP. I've
got hold of the JCSP source from Jim and have it compiled and working
compiled as a Visual J# project. [I've several times wondered about
compiling it as C# but am not sure it would work!]
I would like to know if the way I'm trying to use JCSP is reasonable, and
whether it can be bettered.
The main program logic will be written using normal C# and VB classes (VB
for the UI stuff, mainly). Each of these is designed to be as modular as
possible. Some of them must then be wrapped into processes which bring
everything together.
Unlike Java, C# doesn't let you write code "inline". That is, you can't do
new parallel( new CSProcess() { ...stuff... }).run();
So each thread must have it's own class. After some thought, it seems best
to create these in pairs - a server class which implements CSProcess, and a
client class that shares the same communication protocol elements and does
the wrapping/unwrapping of request and response objects.
So, for my first client, I have a constructor:
public Client(ChannelOutput req, ChannelInput resp)
{
mReq = req;
mResp = resp;
}
And a set of methods which look like:
public bool Login(long code, action how)
{
ServiceReq req = new ServiceReq(ServiceReqCode.Login, code, how);
mReq.write(req);
ServiceReply reply = (ServiceReply)mResp.read();
return reply.code == ServiceRespCode.Success && reply.resp3;
}
While the program classes use, and the server does report, exceptions, at
least for the moment I've chosen not to simulate them on the client.
At the server end, the constructor takes initialisation parameters and the
channels it's using (right types?). It also constructs the "program" object,
in this case, SecurityManager, which is a normal C# class with the usual mix
of internal state, methods and properties:
public Server(string servername, AltingChannelInput[] svrin,
ChannelOutput[] svrout)
{
mSecurityManager = new Stuga.General.SecurityManager(false);
mInputs = svrin;
mOutputs = svrout;
}
The Server object also has a run method, which does something like:
Alternative alt = new Alternative (mInputs);
while (running)
{
int index = alt.fairSelect ();
object obj = mInputs[index].read();
if (obj.GetType() != typeof(ServiceReq))
continue; // someone sent the wrong thing to us!
ServiceReq req = (ServiceReq)obj;
switch (req.code)
{
case ServiceReqCode.IsLoggedIn:
try {
mOutputs[index].write(new
ServiceReply(ServiceRespCode.Success,
mSecurityManager.IsLoggedIn));
}
catch (Stuga.General.LoginException le){
mOutputs[index].write(new
ServiceReply(ServiceRespCode.Exception, le.Message));
}
break;
case ...
}
}
The objects being sent around use an enum for the protocol tag. It uses a
set of variables with "generic" names that are reused as required. I'm not
very happy with that aspect at present and am considering using some sort of
collection so that I only transfer the items required - at present if I need
a given type in one method, it's present in all. On the other hand, the
overhead of creating a collection is fairly high compared to this way...
public enum ServiceReqCode
{
IsLoggedIn, // () -> (resp3)
IsOperatorKnown, // (arg2) -> (resp3)
...
}
public enum ServiceRespCode
{
Success,
...
}
And finally, the transfer object, in this case the request.
public class ServiceReq
{
public ServiceReq() {}
public ServiceReq(ServiceReqCode c, string a1)
{
code = c;
arg1 = a1;
}
public ServiceReq(ServiceReqCode c, long a2)
{
code = c;
arg2 = a2;
}
public ServiceReq(ServiceReqCode c, long a2, action a3)
{
code = c;
arg2 = a2;
arg3 = a3;
}
public ServiceReqCode code;
public string arg1;
public long arg2;
public action arg3;
}
Am I mad yet?
Regards,
Ruth