views:

503

answers:

4

I am not sure if the title formulates it well so sorry.

I basically have a bunch of elements listing targets for a communication. I placed them in a dictionary though i am open to moving them to a different data structure. My problem is that i have a tree-like structure where a key is a branch and each branch has many leaves. Both the branch and the leaves have names stored in strings (cannot be numeral).

private Dictionary < string, string[]> targets;

For each element in the dictionary i must send a communication, and when the target answers i go to the next target and start over. So after searching i am faced with these dilemmas:

  • I cannot use the usual foreach because i need to keep the pointer in memory to pass it in between threads.
  • Since dictionaries are random access it is difficult to keep a pointer
  • When i receive a communication i must verify if the origins are from a target, so i like the dictionary.contains method for that.

I am fairly new at C#, so the answer is probably obvious but i am finding a hard time finding a data structure that fits my needs. What would be the simplest solution? Can somebody suggest anything?

Thank you.


EDIT

I think my post has confused many, and they are sort of stuck on the terms pointers and threads. By threads i don`t mean that they are parallel, simply that i cannot use a foreach or a loop as the next thread that does the next iteration is triggered by incoming communication. This mechanism cannot be changed at the moment, just the iteration must be. By pointer i wasn't referring to the memory pointers often used in C, i just meant something that points to where you are in a list. Sorry i am a Java programmer so i might be using confusing terms.

I noticed the Enumerator is often inherited and that it can be used with structures such as Dictionary and Linked List. Examples i find talk about this sub structure being encapsulated, and shows foreach loops as examples.

Would it be possible to use GetEnumerator() in some way that the enumerator would remember the current position even when accessed through a different thread?

I am off to test these on my own, but if any input from more experienced people is always appreciated!

+1  A: 

You can enumerate over this in parallel using Parallel.ForEach method (from .NET 4). It has been backported as part of the Rx Framework for use in .NET 3.5sp1.

Note - this doesn't actually use one thread per item, but rather partitions the work using the thread pool, based on the hardware thread count of the system on which you're executing (which is usually better...). In .NET 4, it takes advantage of the ThreadPool's new hill climbing and work stealing algorithms, so is very efficient.

Reed Copsey
Thank you. That sounds like the "elegant" solution i was looking for.I haven't upgraded to .net 4, i'll make sure it's not a problem before i do (the client laptops meant to host the application have hardware limitations imposed on me).
Lily
As I mentioned, you can do this in VS2008/.NET 3.5sp1 using the Rx framework, as well.
Reed Copsey
+4  A: 

Hi Lily,

I think you need to re-work your architecture a bit, the Dictionary itself is probably not the data structure you need to use for a ordered iteration.

I would consider moving your tree into a linked list instead.

When you kick off your communications I would suggest having your threads callback a delegate to update your list data, or another shared datastructure that keeps track of where you are in the communication process.

static LinkedList<LeafItem> TreeList = new LinkedList<LeafItem>( );
foreach (LeafItem li in TreeList) {
    Thread newThread = new Thread(
                new ParameterizedThreadStart(Work.DoWork));
    newThread.Start(li);
    }
Tj Kellie
Thank you very much for your answer. I agree that the data structure I chose was probably not the best.I am currently trying to test out the LinkedList method you suggested... but i'm still curious as to if i could do this with a Dictionary using GetEnumerator. It SEEMS to be what i'm looking for (what i meant by pointer, sorry for the confusing terms). I will edit my original post to add details.
Lily
I ended up replacing the dictionary like you said by a LinkedList, though i did not use the foreach part. Thank you for reminding me of this data structure!
Lily
A: 

Edit: from your comments:

My alogrithm is more like: Get the first target Send the message to the first target Thread DIES - Catch a port reception event check if its the right target do some actions - go to the next target start the loop over.

If you want to process the items asynchronously but not in parallel, you should be able to achieve this by copying the dictionary's keys to a Queue<string> and passing both to the callback that handles your asynchronous responses.

Your completion handler pseduo-code might look like this:

// first extract your dictionary, key, and queue from whatever state 
// object you're using to pass data back to the completion event

if (dictionary.Contains(key)) {
    // process the response
}
if (queue.Count > 0) {
    string   key      = queue.Dequeue();
    string[] messages = dictionary[key];
    // send the messages, along with your state data and this callback
}
Jeff Sternal
That is correct, however every single documentation uses the foreach, which is useless in my case. My alogrithm is more like:Get the first targetSend the message to the first targetThread DIES-Catch a port reception event check if its the right targetdo some actions-go to the next targetstart the loop over.So you see, I cannot have a foreach loop because the thread dies eventually, only to be re-awakened (or rather a new thread starts) by a event, usually "OnReceive".
Lily
I think I have it now - you aren't processing the items in parallel, but you are processing them asynchronously **and** you just want to kick the iteration off with a statement like messages.Process() - is that right? I've updated my answer to take another swing at it, given all that.
Jeff Sternal
Thank you! i had an idea earlier about queues but your algorithm helped me get a clearer head. In the end i ended up using the same algorithm as you but using a LinkedList to replace my dictionary and a LinkedListNode to act as iterator, replacing the current node with it's own .Next property.Thank you very much
Lily
A: 

this one is a slight long shot, and I suspect I've messed it up somewhere here :/

basically the idea is to create a custom IEnumerator for your dictionary. The idea being that it contains a static variable that keeps the "location" of the enumeration, for continuing.

the following is some skeleton code for something that does work for pausing and restarting.

public class MyDictEnumerator<T> : IEnumerator<T>
{
    private List<T> Dict;
    private static int curLocation = -1;

    public MyDictEnumerator(List<T> dictionary)
    {
        Dict = dictionary;
    }

    public T Current
    {
        get { return Dict[curLocation]; }
    }

    public void Dispose()
    { }

    object System.Collections.IEnumerator.Current
    {
        get { return Dict[curLocation]; }
    }

    public bool MoveNext()
    {
        curLocation++;
        if (curLocation >= Dict.Count)
            return false;
        return true;
    }

    public void Reset()
    {
        curLocation = -1;
    }
}

Then to use:

            MyDictEnumerator<KeyValuePair<string, int>> enumer = new MyDictEnumerator<KeyValuePair<string, int>>(test.ToList());

        while (enumer.MoveNext())
        {
            Console.WriteLine(enumer.Current.Value);
        }

I'll admit that this isn't the cleanest way of doing it. But if you break out of the enumerator, and create a new one on another thread, then it will continue at the same point (i think :/)

I hope this helps.

Alastair Pitts