开发者

recursively calling method (for object reuse purpose)

I have a rather large c开发者_高级运维lass which contains plenty of fields (10+), a huge array (100kb) and some unmanaged resources. Let me explain by example

class ResourceIntensiveClass
{
    private object unmaganedResource; //let it be the expensive resource
    private byte[] buffer = new byte[1024 * 100]; //let it be the huge managed memory
    private Action<ResourceIntensiveClass> OnComplete;


    private void DoWork(object state)
    {
        //do long running task
        OnComplete(this); //notify callee that task completed so it can reuse same object for another task
    }

    public void Start(object dataRequiredForCurrentTask)
    {
        ThreadPool.QueueUserWorkItem(DoWork); //initiate long running work
    }
}

The problem is that the start method never returns after the 10000th iteration causing a stack overflow. I could execute the OnComplete delegate in another thread giving a chance for the Start method to return, but it requires using extra cpu time and resources as you know. So what is the best option for me?


Is there a good reason for doing your calculations recursively? This seems like a simple loop would do the trick, thus obviating the need for incredibly deep stacks. This design seems especially problematic as you are relying on main() to setup your recursion.


recursive methods can get out of hand quite fast. Have you looked into using Parallel Linq? you could do something like

(your Array).AsParallel().ForAll(item => item.CallMethod());

you could also look into the Task Parallel Library (TPL)

with tasks, you can define an action and a continue with task.

The Reactive Framework (RX) on the other hand could handle these on complete events in an async manner.


Where are you changing the value of taskData so that its length can ever equal currentTaskIndex? Since the tasks you are assigning to the data are never changing, they are being carried out forever...


I would guess that the problem arises from using the pre-increment operator here:

 if(c.CurrentCount < 10000)
    c.Start(++c.CurrentCount);

I am not sure of the semantics of pre-increment in C#, perhaps the value passed to a method call is not what you expect.

But since your Start(int) method assigns the value of the input to this.CurrentCount as it's first step anyway, you should be safe replacing this with:

 if(c.CurrentCount < 10000)
    c.Start(c.CurrentCount + 1);

There is no point in assigning to c.CurrentCount twice.


If using the threadpool, I assume you are protecting the counters (c.CurrentCount), otherwise concurrent increments will cause more activity, not just 10000 executions.


There's a neat tool called a ManualResetEvent that could simplify life for you.

Place a ManualResetEvent in your class and add a public OnComplete event.

When you declare your class, you can wire up the OnComplete event to some spot in your code or not wire it up and ignore it.

This would help your custom class to have more correct form.

When your long process is complete (I'm guessing this is in a thread), simply call the Set method of the ManualResetEvent.

As for running your long method, it should be in a thread that uses the ManualResetEvent in a way similar to below:

private void DoWork(object state)
{
    ManualResetEvent mre = new ManualResetEvent(false);
    Thread thread1 = new Thread(
      () => {
      //do long running task
      mre.Set();
    );
    thread1.IsBackground = true;
    thread1.Name = "Screen Capture";
    thread1.Start();
    mre.WaitOne();
    OnComplete(this); //notify callee that task completed so it can reuse same object for another task
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜