We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › How do I use the run() method in a new thread
Pages: 1 2 
How do I use the run() method in a new thread? (Read 1139 times)
How do I use the run() method in a new thread?
Jun 9th, 2009, 2:26pm
 
Just a quick question about the run() method when creating a new thread. I'm going off of Ben Fry's example on this post about multi-threading. As I understand it, the run() method is called when the constructor is called, and some separately-threaded block of code runs. But if I call the run() method again separately (i.e. after it's done running from the constructor setup) from the parent's draw() method (under some condition), will the run() method still execute on a separate thread

Here's the scenario I'm trying to accomplish. I've got a project which polls various twitter feeds, then displays the posts graphically in the display window. Since I'm polling 20+ websites, there is as much as a 45-60 second delay in the draw() method every time I poll the sites. So I'd like to be polling the sites in a different thread so that my graphics can draw uninterrupted. So in my draw() method, I'm making a call to run() every 60 seconds. But I'm still getting the hiccup while the system sends the GET requests out.

Should I instead have the run() method looping endlessly and put the polling timers within that Or can I make a call to run() from the draw method whenever I want and have it execute code on a different thread I can post some code if it will help, but the file is large and complex, so it might have to be a pseudo example.
Re: How do I use the run() method in a new thread?
Reply #1 - Jun 9th, 2009, 10:04pm
 
You can call the run() method of another thread, but it will not execute as another thread.
Code:
class T extends Thread {

 T() {
 }
 T(String threadName) {
   super(threadName); // Initialize thread.
   //System.out.println(this);
   start();
 }
 
 public void run() {
   //If executed by the JVM, this will show its own name
   //If called by another thread, it will show that thread's name
   System.out.println(Thread.currentThread().getName() + "|Sub thread");
 }
}


void setup() {
 Thread tr = new T("sub thread");

 try {
   //delay for one second
   Thread.currentThread().sleep(1000);
 } catch (InterruptedException e) {}

 System.out.println(Thread.currentThread() + "|Main thread");

 tr.run();
}

Edit: I knew there was a better way (something I have used before)...
Code:
javax.swing.Timer clock;

ActionListener timeCatcher = new ActionListener() {
 public void actionPerformed(ActionEvent e) {
   //Do your stuff
   
   println("test");

 }
};

void setup() {

 //delay is in milliseconds
 int delay = 1000;
 clock = new javax.swing.Timer(delay, timeCatcher);

 clock.start();
}
Re: How do I use the run() method in a new thread?
Reply #2 - Jun 10th, 2009, 1:03am
 
The javax.swing.Timer class does not create a new thread rather it generates ActionEvent objects and places them on the event queue to wait for its turn. This happens in the main event despatch thread so if the code inside the ActionPerformed method takes a long time it will make the program unresponsive (slow down) which is what NoChinDeuxe wants to avoid. The Timer class is great for executing small bits of code at regular intervals and because it runs in the main thread it can share the data from the twitter feeds no problem.
More info at
http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html

The first example from NoahBuddy uses the Thread class which as stated creates a new thread which runs parallel to the main thread. The disadvantage here is accessing the twitter data - the main thread wants to display the twitter data and the thread wants to update the twitter data this can cause conflicts that can cause the program to fail. There are techniques you can use to avoid this conflict e.g. semaphores, locks etc.
Smiley
Re: How do I use the run() method in a new thread?
Reply #3 - Jun 10th, 2009, 1:39am
 
Just had a coffee and it has stimulated the grey matter.

In the post you said you were polling 20+ websites, the idea I had was to have an array or Arrayist to remember the website URLs then use the ActionPerformed method in javax.swing.Timer to poll 1 website at a time.

I have never used Twitter so I don't know if this is a practical solution but there have been other posts on polling Twitter so you might search the discourse for more info.

Another thought:

It is common for the run() method to be an infinite loop so would only be called once from setup() rather than draw(). To safely stop the thread you can use a boolean variable to stop the loop e.g.
Code:


public void run(){
 while(wanted == true){
   // your stiuff

 }
}

wanted would be an attribute of the class which is set to true. When it is set to false the loop exits the run method ends and the thread is destroyed. To restart the thread set wanted to true and call run() again.

Hope all this helps Smiley
Re: How do I use the run() method in a new thread?
Reply #4 - Jun 10th, 2009, 7:02am
 
Thanks for the info guys. So maybe you can help me clarify something. If I call my thread's constructor in setup() and loop the run() function like you mentioned, that run() function will continue looping while the rest of my program moves on to the draw() method. Is that correct? In other words, my program won't endlessly stay in setup() until that run() method finishes, right?

If that's the case, then I may have a solution. Quark mentioned that the program may have issues reading and updating the data at the same time. Since I'm basically grabbing one long string from the latest post on each Twitter page, I thought about writing a text file with the current String into the data folder. Then, the main thread (which contains the drawing objects and methods) will check the text files in the data folder to see if there are new posts available. Do you think I could still run into problems with the program trying to check a text file while the other thread is trying to overwrite existing text files?  
Re: How do I use the run() method in a new thread?
Reply #5 - Jun 10th, 2009, 8:05am
 
Quote:
If I call my thread's constructor in setup() and loop the run() function like you mentioned, that run() function will continue looping while the rest of my program moves on to the draw() method. Is that correct? In other words, my program won't endlessly stay in setup() until that run() method finishes, right?


My mistake we will remain forever in setup() the solution is in the code example below.

Quote:
Do you think I could still run into problems with the program trying to check a text file while the other thread is trying to overwrite existing text files?  


Yes

One way round this is to have a variable that is shared between the threads that indicates who has access to the data.

I assume that all your code is in a single file, if that is the case then a variable created outside the your Thread class will be available throughout the code.

Code:

boolean locked = true;
boolean updating_enabled = true;

void setup(){
 // create an object (eg myTwitterReader) from the
 // class that extends Thread
 // call myTwitterReader.start()
 // do not call run()
}

void stop(){
   updating_enabled = false;
}

void draw(){
 if(locked == false){
   locked = true;
   // do the using data to draw stuff here
   
   locked = false;
 }
}

In the run method
Code:


void run(){
 while(updating_enabled == true){
   if(locked == false){
     locked = true;
     // read the Twitter feeds
     locked = false;
     try{
        sleep(1000); // sleep for 1 second give draw() a chance
     }
     catch (Exception e){
     }
   } // end of if statement
 }// end of while loop
}


The thread will run until you set updating_enabled to false

The stop method is called by Processing when you end the program otherwise the running thread might stop your program closing.

Using this you don't need to use a text file you can read the Twitter feeds into a String or whatever since draw() and run() cannot access the data at the same time.

I typed this directly into this post so might be odd typo error.

Hope this helps. Smiley
Re: How do I use the run() method in a new thread?
Reply #6 - Jun 10th, 2009, 8:27am
 
I see what you mean. I tried a simple combination of the two pieces of code and the ActionEvent reports as AWT-EventQueue-0 as the thread name (my confusion was from that).

With any animation, it is definitely slow...
Re: How do I use the run() method in a new thread?
Reply #7 - Jun 10th, 2009, 9:59am
 
I created a test project to see if setup() would loop endlessly while run() looped endlessly. Here's the test code:

Code:

ThreadThing tt;

void setup(){
 size(100,100);
 frameRate(30);

 tt = new ThreadThing(this);
 tt.start();
}

void draw(){
 background(255);
 if(frameCount%180 == 0){
   println("          EXECUTING DRAW METHOD");
 }
}

void keyPressed(){
 if(key == ' '){
   tt.stopThread();
 }
}

public class ThreadThing implements Runnable {
 Thread thread;
 boolean runThread;

 public ThreadThing(PApplet parent) {
   parent.registerDispose(this);
   runThread = true;
 }

 public void start() {
   thread = new Thread(this);
   thread.start();
 }

 public void run() {
   while(runThread){
     if(frameCount%150 == 0){
       println("thread still running");
     }
   }
 }
 
 public void stopThread(){
   runThread = false;
 }

 public void stop() {
   thread = null;
 }

 public void dispose() {
   stop();
 }
}


If you execute the above code, the thread will keep reporting "thread still running" at the same time that the draw() method reports "EXECUTING DRAW METHOD," which means that we actually run both threads at once, even though we only started the extra thread in setup(). If you press the spacebar, you'll turn the extra thread off. So basically, I think I could create a thread class which does all my web polling, but it'll only update the global String variables with the new posts if my access booleans (per Quark's suggestion) allow it. I think at this point I just need to get started coding to see if I can make this work. Thanks again for your help, everyone. I'll update when I get something working...
Re: How do I use the run() method in a new thread?
Reply #8 - Jun 10th, 2009, 10:17am
 
OK, just tried implementing all this stuff and it works like a dream! So thanks for the input. The graphics run seamlessly while the web polling continues on in the background. It was rather simple, really. I just created a thread class and put my polling timer in that:

Code:

public void run() {
   while(runThread){
     if(frameCount%1800 == 0){
       for(int i=0; i<tweets.size(); i++){
         Tweet t = (Tweet)tweets.get(i);
         t.setLines();
         if(t.newPostIsReady == true){
           TextMessage tm = new TextMessage(t.getLines());
           messages.add(tm);
           t.newPostIsReady = false;
         }
       }
     }
   }
 }


Since all my objects are global and completely public, I was able to access them without a problem. I've been letting it run for a while, and so far I haven't run into any data access problems, so I may not even need the access booleans. We'll see. Thanks again!
Re: How do I use the run() method in a new thread?
Reply #9 - Jun 10th, 2009, 10:30am
 
Glad it worked out I notice that you store the TextMessage object in 'messages' just out of interest what type of object is it ArrayList, LinkedList ... ?
Re: How do I use the run() method in a new thread?
Reply #10 - Jun 10th, 2009, 1:10pm
 
It's an ArrayList. My TextMessage objects get fed String[] from the Tweet objects, and they parse and format the text into little speech baloons that appear on the screen and float around.
Re: How do I use the run() method in a new thread?
Reply #11 - Jun 11th, 2009, 2:03am
 
I asked because Java does provide some thread safe collections although they are not as easy to use as arraylist.

The reason you are probably not getting access problems is because you are reading the feeds once every 1800 frames (~every 30 seconds) so the chance that you have concurrent access (ie draw using 'messages' at the same time as the run method) is very small but not impossible!

If you run into access problems then it is easy to modify your run function to make it thread safe. Using the locked variable previously discussed -

Code:
public void run() {
   while(runThread){
     if(frameCount%1800 == 0){
       // wait for lock to be released by draw
       while(locked == true){
         try{
           sleep(100); // sleep for 0.1 second give draw() a chance
         }
         catch (Exception e){
         }

       } // end while locked    
       // now lock for reading tweets
       locked = true;
       for(int i=0; i<tweets.size(); i++){
         Tweet t = (Tweet)tweets.get(i);
         t.setLines();
         if(t.newPostIsReady == true ){
           TextMessage tm = new TextMessage(t.getLines());
           messages.add(tm);
           t.newPostIsReady = false;
         } // end if
       } // end for
       locked = false;
     } // end if framecount
   }
 }


then in draw only access 'messages' when locked = false ie

Code:
void draw(){
 if(locked == false){
   locked = true;
   // do the using data to draw stuff here
   
   locked = false;
 }
}


Anyway have to go look forward to seeing your app in the Exhibition forum
Cheesy
Re: How do I use the run() method in a new thread?
Reply #12 - Jun 11th, 2009, 6:31am
 
I've seen the sleep() method used before. What does that do, just delay the thread from looping again for a certain number of milliseconds?
Re: How do I use the run() method in a new thread?
Reply #13 - Jun 11th, 2009, 6:51am
 
The sleep method will pause the thread at the point it was called for the number of milliseconds indicated after that time the thread will continue running at the next statement outside the try/catch block. This allows any other threads more CPU time to do their thing.

In the example code the run method must stop if locked == true because the draw method has control of the data - this just gives the draw thread more CPU time to finish its task and unlock the data.
Re: How do I use the run() method in a new thread?
Reply #14 - Jun 12th, 2009, 9:50am
 
Hey Quark, in case you are interested in seeing a screen shot of a little test run of my twitter app, you can check it out by visiting this site. For some reason, the messages in the background didn't really show up well with their low alphas, but you can see the New York Times post coming in in real time in the center, as well as a Puff Daddy post that recently came in as well. The other little red dots are all posts as well, but like I said, their low alpha is making them difficult to see in the screen shot.
Pages: 1 2