TakeMeAsAGuest
TakeMeAsAGuest

Reputation: 995

recursively calling method (for object reuse purpose)

I have a rather large class 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?

Upvotes: 0

Views: 554

Answers (6)

user153923
user153923

Reputation:

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
}

Upvotes: 0

Alex
Alex

Reputation: 4934

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...

Upvotes: 1

Haplo
Haplo

Reputation: 1368

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

Upvotes: 0

matt b
matt b

Reputation: 140011

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.

Upvotes: 0

dlev
dlev

Reputation: 48596

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.

Upvotes: 3

Alexandre Brisebois
Alexandre Brisebois

Reputation: 6743

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.

Upvotes: 1

Related Questions