CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    Apr 2008
    Posts
    6

    Getting an object from a different thread

    Ok, I've done some googling, searched these forums, but I couldn't find the answer to my problem. So here it is:
    I've got a function in a class that creates a new thread which creates an XMLDocument object and downloads data into it. After it is finished it should somehow pass on that XMLDocument to the main thread (that runs the class, so to speak) so I can get data from it.
    So I don't have to access any data while the thread is running, if that makes a difference (and I think it does, from what I've seen so far).

    So far the only code I've got working is the code without sharing the XMLDocument when finished, and it is this:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml;
    using System.Net;
    using System.IO;
    using System.Windows.Forms;
    using System.Threading;
    using System.Drawing;

    namespace Lolcats
    {
    class LolcatsRss
    {

    private string url = "http://this/is/my/rss/url";

    XmlDocument xmlDoc;
    Thread webThread;

    public LolcatsRss()
    {
    Thread webThread = new Thread(new ThreadStart(getRss));
    webThread.Start();
    }

    public void getRss() {
    XmlDocument _xmlDoc = new XmlDocument();
    _xmlDoc.Load(url);
    }
    }
    }


    I've tampered with some delegates, but nothing that didn't throw a theading-related exception, so obviously not the right way. Who can enlighten me?

  2. #2
    Join Date
    Apr 2008
    Posts
    6

    Re: Getting an object from a different thread

    Quick fix (I can't edit my post (?)):
    System.Windows.Forms was only there to be able to show a messagebox every now and then, it's not there for any serious purpose and will be removed again, so this is not some kind of control or form, might that not have been clear already.
    System.Windows.Drawing is there because there's some image-processing to be done once the XmlDocument is downloaded.

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Getting an object from a different thread

    One way to do this is to create an event in the LolcatsRss class and a public XmlDocument property.

    Users of this class would then subscribe to the event.

    When the thread completes loading the document, if fires the event.

    In the event handler, the user of the class would using the public property to access the xmldoc.

  4. #4
    Join Date
    Jul 2006
    Posts
    297

    Re: Getting an object from a different thread

    Well Arjay suggested what I was about to explain. Since its a rather complicated solution and hard to explain unless you already know how to work with events I made a little program to show you what hes talking about.

    Hope this example helps, i tried to document it the best I could so you would understand whats going on. It works for me, basically it loads an xml document from a thread and populates a ListBox from the nodes it read from the xml document.
    Attached Files Attached Files

  5. #5
    Join Date
    Apr 2008
    Posts
    6

    Re: Getting an object from a different thread

    The thing is: that's not really what I want to do.
    I have 2 threads within the rss-class, one 'main' thread that's running the rss-class, and my other thread that downloads the XML. When the XML-downloading is done, I want the main thread (that's running the rss-class) to have access to the XmlDocument to get some values from it. The XmlDocument does not need to be shared between classes, only between the two threads within that class.

  6. #6
    Join Date
    Jul 2006
    Posts
    297

    Re: Getting an object from a different thread

    If you already have a thread that the rss-class is running in then why do you need a second thread to download the xml? You're not blocking the UI or anything. You can't just return a object from a thread when the thread is done. You have to fire some event letting the other thread know that the resources are available to use. As soon as the thread that downloads the xml starts, the thread calling it continues. It can't wait for the thread (if it did you wouldn't be using a thread) to return some value.

  7. #7
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Getting an object from a different thread

    Monalin is right - why use a thread in the first place. If you have thread A blocking until thread B has loaded the xml document, why not just load the xml document in thread A ?

    Code:
    The XmlDocument does not need to be shared between classes, only between the two threads within that class.
    I think you're confused. A 'thread' is not a member of any class - it is an execution path. As such it can (and does) go everywhere and anywhere, access any data it pleases just as the main thread can.

    Threads are not related to classes, it's just in .NET you have a thread class to manage them and enable you to refer to them.

    Darwen.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  8. #8
    Join Date
    Apr 2008
    Posts
    6

    Re: Getting an object from a different thread

    Quote Originally Posted by darwen View Post
    Monalin is right - why use a thread in the first place. If you have thread A blocking until thread B has loaded the xml document, why not just load the xml document in thread A ?

    Code:
    The XmlDocument does not need to be shared between classes, only between the two threads within that class.
    I think you're confused. A 'thread' is not a member of any class - it is an execution path. As such it can (and does) go everywhere and anywhere, access any data it pleases just as the main thread can.

    Threads are not related to classes, it's just in .NET you have a thread class to manage them and enable you to refer to them.

    Darwen.
    Yeah, some poor choice of words there on my behalf. The 'main' thread runs both the UI and loads the rss-class. Then the rss-class spawns another thread to download the XML. When that is done, the thread that runs both the GUI and the rss-class should be notified and presented somehow with the XmlDocument so it can get some data from the Xml to pass on to the GUI.
    I don't want to invoke controls or anything like that, I want to keep it all separated so it's usable in lots of different projects...

  9. #9
    Join Date
    Jul 2006
    Posts
    297

    Re: Getting an object from a different thread

    Quote Originally Posted by graey View Post
    Yeah, some poor choice of words there on my behalf. The 'main' thread runs both the UI and loads the rss-class. Then the rss-class spawns another thread to download the XML. When that is done, the thread that runs both the GUI and the rss-class should be notified and presented somehow with the XmlDocument so it can get some data from the Xml to pass on to the GUI.
    I don't want to invoke controls or anything like that, I want to keep it all separated so it's usable in lots of different projects...
    By modifying my example code i attached slightly you can do just that. I believe my code does what you're looking for. You just need to tweak it a little to work with your system. The same principles apply.


    "Then the rss-class spawns another thread to download the XML" - DOES IT

    " When that is done, the thread that runs both the GUI and the rss-class should be notified" - DOES IT (via an event)

    " and presented somehow with the XmlDocument so it can get some data from the Xml to pass on to the GUI" - DOES IT

    If you don't understand the code i attached please ask questions. I think using events and callback functions are the only way you can accomplish what you're trying to do. Heres the slightly modified code, just change Form1.cs to this...

    Code:
            public XmlDocument xml = new XmlDocument();
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void populateNames_Click(object sender, EventArgs e)
            {
                // Create a new instance of the names class
                Names myNames = new Names();
    
                // Register the event to fire when we have the xml data
                myNames.PopulateNamesComplete += new PopulateNamesCompleteEventHandler(populateNames_Complete);
    
                // Start the new thread
                myNames.LoadNames();
            }
    
            private void populateNames_Complete(Object sender, PopulateNamesCompleteEventArgs e)
            {
                // When this thread gets called its still running in the other thread so you can't
                // access any of the UI controls on the form unless you do so through a delegate funciton
                // if you just wanted to assign a variable you can still do that without invoking
                // a delegate method.
    
                xml = e.Xml;
    
                // Show the xml just so you know it completed.
                MessageBox.Show(xml.OuterXml);
            }

  10. #10
    Join Date
    Apr 2008
    Posts
    6

    Re: Getting an object from a different thread

    Ah, pass it as part of the event arguments, hadn't noticed that yet, sorry. That indeed seems like it will work exactly like I want it to! I'll change it so that the rss-class is listening to the event itself and then it should work exactly like I want. Thanks!

  11. #11
    Join Date
    Jul 2006
    Posts
    297

    Re: Getting an object from a different thread

    Quote Originally Posted by graey View Post
    Ah, pass it as part of the event arguments, hadn't noticed that yet, sorry. That indeed seems like it will work exactly like I want it to! I'll change it so that the rss-class is listening to the event itself and then it should work exactly like I want. Thanks!
    Yup, thats the cool thing about events. You can pass whatever variables you want through the EventArgs. You can even change the PopulateNamesCompleteEventArgs class so that it can send more than XmlDocuments just by adding more properties.

  12. #12
    Join Date
    Apr 2008
    Posts
    6

    Re: Getting an object from a different thread

    Quote Originally Posted by monalin View Post
    Yup, thats the cool thing about events. You can pass whatever variables you want through the EventArgs. You can even change the PopulateNamesCompleteEventArgs class so that it can send more than XmlDocuments just by adding more properties.
    I see. It's working now, but there's one minor thing I still don't like.
    Right now the rss-class creates a thread that downloads xml, processes the xml itself so that a public property of the rss-class is filled. Then it fires an event, and that's where the main thread (that also runs the GUI) picks it up. Right now I need delegates and invokes in my main thread, while I'd rather see 'normal' calls there with the delegates only in the class that actually does some (multi)threading. I've been tinkering with the code but I can't get it to work that way, yet I've seen libraries that do this (though sadly enough only binaries, no source).
    (I want it to work that way because it's a class library that should be easy to use for novice programmers, the threading-stuff safely hidden from the users of the class lib).

  13. #13
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Getting an object from a different thread

    Another way to approach this is to pass in the WindowsFormsSynchronizationContext to the Names class, then use the Post method.

    Code:
    privatevoid populateNames_Click(object sender, EventArgs e)
    {
      // Create a new instance of the names class
      // Pass in the current UI synchronization context
      Names myNames = Names.Create( WindowsFormsSynchronizationContext.Current );
     
      // Register the event to fire when we have the xml data
      myNames.PopulateNamesComplete += new
    PopulateNamesCompleteEventHandler(populateNames_Complete);
     
      // Start the new thread
      myNames.LoadNames();
    }
    


    The Names class is modified to use the SynchronizationContext

    Code:
    
    
    Code:
    // This is the entry point for the thread we use to load the names
    privatevoid StartLoadNames()
    {
      XmlDocument xml = newXmlDocument();
     
      // You can load the xml document from a url here instead. I just did this cause its simple.
      xml.LoadXml("<names><name>Brian</name><name>Jerry</name><name>Andrew</name></names>");
     
      // Use the passed in SynchronizationContext to post
      // to the UI context
      object state = newobject[] { xml };
      _context.Post(OnPostToUIContext, state);
    }
     
    // This runs in the UI thread context
    // It just fires the PopulateNamesCompleted event
    privatevoid OnPostToUIContext(object state)
    {
      XmlDocument xml = ((XmlDocument)((object[])state)[0]);
    
     
      // Fire the event.
      OnPopulateNamesComplete(newPopulateNamesCompleteEventArgs(xml));
    }
    


    This is a very quick representation, so the code can definitely be cleaned up.

    Attached Files Attached Files

  14. #14
    Join Date
    Jul 2006
    Posts
    297

    Re: Getting an object from a different thread

    *edit*

    Arjay beat me to it.

    Looks like this is exactly what you need. I didn't know you could do this Arjay I was trying to find a way to accomplish this the other day when I was writing this sample but couldn't find anything.
    Last edited by monalin; August 14th, 2009 at 12:42 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured