Multi-threaded command runner

0 views
Skip to first unread message

Bill Barry

unread,
May 8, 2008, 4:03:27 PM5/8/08
to castle-pro...@googlegroups.com
I am playing around with a multi-threaded command interface and so far I
have this; I was wondering if any of you see any problems with it or
things that could be done better. My naive tests suggest that this
works, but I am not certain. The commands that will run will not have
knowledge of each other (I am trying to write a replacement for Cassini
because it can't be redistributed and because I want to deepen my
understanding of how it works; ultimately I hope to make the full source
available, maybe as a contribution to Castle [right now cassini.dll is
included with the built dlls and I don't think it is allowed to be]):


public interface ICommand {
void DoWork();
}
public class CommandRunner {
readonly ThreadCounter threadCounter = new ThreadCounter();
public List<ICommand> workItems = new List<ICommand>();
private bool isStopping;

public void StartWorkItems() {
while(workItems.Count>0) {
if (!isStopping) {
var item = workItems.First();
workItems.RemoveAt(0);
ThreadPool.QueueUserWorkItem(DoWorkItem, item);
} else {
Thread.Sleep(250);
}
}
}

private void DoWorkItem(object state) {
using(threadCounter.CountableThread()) {
((ICommand)state).DoWork();
}
}

public void WaitForWorkToFinish() {
isStopping = true;
threadCounter.WaitForPendingThreadsToFinish();
isStopping = false;
}
}

public class ThreadCounter {
private readonly object lockobject = 0;
private int _count;

public sealed class WorkingThread:IDisposable {
private readonly ThreadCounter _reference;

public WorkingThread(ThreadCounter reference) {
_reference = reference;
}

void IDisposable.Dispose() {
lock (_reference.lockobject) {
_reference._count--;
}
}
}

public void WaitForPendingThreadsToFinish() {
int count;
lock (lockobject) {
count = _count;
}
while (count > 0) {
Thread.Sleep(250);
lock (lockobject) {
count = _count;
}
}
}

public WorkingThread CountableThread() {
lock (lockobject) {
_count++;
}
return new WorkingThread(this);
}
}

Derek Ekins

unread,
May 8, 2008, 4:24:12 PM5/8/08
to castle-pro...@googlegroups.com
If you want a cassini replacement look at xsp from mono.

2008/5/8 Bill Barry <after....@gmail.com>:

Bill Barry

unread,
May 8, 2008, 5:40:28 PM5/8/08
to castle-pro...@googlegroups.com
Afiak xsp doesn't quite replace cassini. It is more powerful from the
command line, but it is quite a bit more complex because of that; I am
sure someone could write a wrapper to produce essentially the same
interface, but I don't really care to do that and it doesn't help me
with what I want to do.
Right now all I need to do in order to be able to start up a server is
create this program and place it in the bin directory of the site along
with the server dll:

internal class Program {
private static void Main(string[] args) {
var server = new Server(8181, "/asdf", @"C:\TestSite\");
server.Start();
bool TurningOff = false;
while (!TurningOff) {
if (Console.KeyAvailable) {
TurningOff = true;
}
Thread.Sleep(500);
}
server.Stop();
}
}

It is also very simple to encapsulate that logic in the SetUpFixture and
TearDownFixture of my test library; which you can see being done with
Cassini.dll in
https://svn.castleproject.org/svn/castle/trunk/MonoRail/Castle.MonoRail.TestSupport/WebServer.cs

The issue is more that I am seeking an understanding of how this works,
not that I merely want to replace cassini (and after I posted the
previous email, I went and reread the cassini eula and couldn't find the
part saying you can't redistribute it in compiled form). In coming to
such an understanding I will have a replacement for Cassini.dll simply
because I will have written one. I don't particularly care that Cassini
or xsp exist, and would probably be writing my own toy app even still.
I've already learned several things about ASP.NET running from a command
line that I didn't already know:

I've learned ASP.NET has to run in a different app domain (or at least
the domain needs to be modified, I am not sure exactly what is happening
there, only that I am doing it correctly) from the server and sockets
running from a console app

I now know why exactly you do need MarshalByRefObject (previously I just
noticed it was the base object for all collections and had no idea what
it really did, now I have learned that it is used to proxy classes
across remoting connections, including across app domains)

I've learned a lot about rfc2616 (http/1.1)

I've discovered System.Web.HttpRequest.PathInfo

I've learned that even though System.Net.HttpListener can be used to
create a basic web server and can even be used to process asp.net files,
I can't seem to figure out how to get it to correctly handle postbacks.

And those are just some of the notable things; Also I am getting even
better with my R# commands.

Reply all
Reply to author
Forward
0 new messages