Anzeige:
Ergebnis 1 bis 10 von 10

Thema: Sync-Objekt blockiert, obwohl kein Thread darauf zugreift?

  1. #1
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53

    Sync-Objekt blockiert, obwohl kein Thread darauf zugreift?

    Hallo,

    das ganze hier ist vielleicht trivial, aber für mich gerade unlösbar.
    Ich habe mir ein Programm geschrieben, daß ein ftp-Objekt erzeugt (von den Jakarta-Commons), und danach zwei Threads aufruft: Erstens einer, der 8 Sekunden schläft, dann aufwacht und ein NOOP sendet, damit die Verbindung nicht abbricht; und zweitens einer, der von System.in liest und das als Kommando an die FTP-Verbindung übermittelt.

    Ohne synchronized habe ich logischerweise das Problem, daß der NOOP-Thread eine Operation unterbrechen kann, z.B. ein Verzeichnislisting. Also habe ich die entsprechenden Bereich umbaut und
    Code:
    synchronized(ftp) { ... }
    drumherumgesetzt. Jetzt habe ich das Problem, daß keines der umbauten Bereiche mehr ausgeführt wird, als würden beide darauf warten, daß der Monitor frei wird, obwohl keiner wirklich drin ist.

    Das Programm macht folgendes:
    Code:
    CONNECT
    220-FTP server ready.
    220 This is a private system - No anonymous login
    
    LOGIN
    230-User blah has group access to:  nobody
    230 OK. Current restricted directory is /
    
    NOOP
    Das noop an sich wird aber nichtmehr ausgeführt. Weiß jemand, warum?

    Mein Programm:
    Code:
    /*
     * Created on 24.05.2005
     */
    package testing;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    import org.apache.commons.net.ftp.FTPClient;
    
    public class Ftptest extends Thread {
    	private static String	server	= "xy";
    	private	static int		port	= 21;
    	private	static String	user	= "blah";
    	private static String	pass	= "blubb";
    	private static FTPClient ftp	= new FTPClient();
    	private static BufferedReader br;
    	private static int		reply;
    
    	private static final int LIST = 0;
    	
    	static class InputListener extends Thread {
    		public InputListener( ) {
    			br =
    				new BufferedReader(
    				new InputStreamReader(System.in)
    			);
    		}
    		
    		public void run() {
    			while(!isInterrupted()) { try {
    				if(ftp.isConnected()) {
    					String s = br.readLine();
    					if(s != null && !s.equals("") && !s.equals("\\n")) {
    						System.out.println("========== "+s+" ==========");
    						synchronized(ftp) {
    							if(s.compareToIgnoreCase("LIST") == 0) {
    								for(int i =0; i< ftp.listNames().length;++i)
    									System.out.println(s+": "+ftp.listNames()[i]);
    							} else { ftp.sendCommand(s);
    							for(int i = 0; i < ftp.getReplyStrings().length;i++) 
    								System.out.println(s+": "+ftp.getReplyStrings()[i]);
    							}	
    							ftp.notify();
    						}
    					} 	
    				}
    			} catch (Exception e) {
    				System.err.println(e.toString());
    			} }
    		}
    	}
    	
    	static class FtpListener extends Thread {
    		public void run() {
    			while(!isInterrupted() && isAlive()) {
    			try {
    				if(!ftp.isConnected()) {
    					System.out.println("CONNECT");
    					ftp.connect(server,port);
    					System.out.println(ftp.getReplyString());
    					System.out.println("LOGIN");
    					ftp.login(user,pass);
    					System.out.println(ftp.getReplyString());
    				}
    				synchronized(ftp) {
    					System.out.println("NOOP");					
    					ftp.sendNoOp();
    					System.out.println(ftp.getReplyString());
    					ftp.notify();
    				}
    				sleep(8000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    				try {
    					ftp.logout();
    					ftp.disconnect();
    				} catch (IOException ex) { 
    					// nothing. We just ensure that no connection keeps
    					// alive, bumping around somewhere.
    				}
    			} catch (IOException e) {
    				interrupt();
    			}
    		} }
    	}
    	
    	public static void main (String[] args) {
    		try {
    			FtpListener in = new FtpListener();
    			//in.setDaemon(true);
    			in.start();
    			
    			Ftptest.InputListener inlistener = new InputListener();
    			inlistener.start();
    			in.join();
    			inlistener.join();
    			
    		} catch (Exception e) {
    			e.printStackTrace();
    		}	
    	}
    }

  2. #2
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Passiert das auch wenn du keinen Output auf System.out machst?

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  3. #3
    Registrierter Benutzer Avatar von RogerJFX
    Registriert seit
    13.04.2005
    Beiträge
    35
    schreib einfach in Deine Hauptklasse
    Code:
    static void handleThreads (Thread thread) {
    
      try{
         thread.wait();
      }
      catch (IllegalMonitorStateException il) {
        ; // das wird vor allem am Anfang vorkommen
      }
      catch (Exception e) {
      ;
      }
      notifyAll();
    }
    Und jetzt in jeder run() - Methode der zwei Threads immer zum Schluß handleThreads(this) aufrufen.

    Sollte klappen. Allerdings solltest Du gleich am Anfang (im Konstruktor) das Gleiche tun, was mindestens einmal die IllegalMonitorStateException auslösen wird, da der betreffende Thread den Monitor noch nicht besitzt. Aber Sch... drauf!

    Ach so! Und schmeiß das join() raus. Braucht kein Mensch.

    Cheers,

    Roger
    if you can't dazzle em with brillance, baffle em with bullshit

  4. #4
    Registrierter Benutzer Avatar von RogerJFX
    Registriert seit
    13.04.2005
    Beiträge
    35
    join() bedeutet einfach nur, daß ein zweiter Thread drangehängt wird. Das heißt, daß der Thread, in dem join() steht, erst dann fertig ist, wenn der gejointe Thread auch durch ist. Ganz wie bei der Eisenbahn. Die Schranken gehen erst dann hoch, wenn der letzte (gejointe) Wagon vorbeigefahren ist .

    Cheers,

    Roger
    if you can't dazzle em with brillance, baffle em with bullshit

  5. #5
    Registrierter Benutzer Avatar von RogerJFX
    Registriert seit
    13.04.2005
    Beiträge
    35
    Oh! Jetzt habe ich nochmal genauer hingesehen.

    Warum schreibst Du nicht einfach

    public synchronized void run() {
    while(true) { // oder sonst eine Bedingung
    // mach was, und wenn es gut ist: break;
    // wenn nicht, throw irgendne Exception und auch break;

    ???

    Das "while(true)" sperrt ja dann automatisch, da die ganze Methode synchronized ist. M.E. sperrst Du schlicht zu spät. Das gibt irgendwann einen schönen Knoten in der Leitung.

    Oder irre ich hier?

    Cheers,

    Roger
    if you can't dazzle em with brillance, baffle em with bullshit

  6. #6
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    @RogerJFX: Das Einfügen von synchronized bringt leider nichts. Deine handleThread-Routine habe ich nicht verstanden, was bewirkt die?

    @anda_skoa: Ohne System.out habe ich keine Möglichkeit, das Programm zu testen -- ich habe keinen Zugriff zu irgendwelchen FTP-Logs. Ist System.out nicht threadsicher?

    Ich habe noch einige Zeit rumgesucht und bin auf das hier gestoßen...
    Q: Are the Commons-Net classes thread-safe? For example, can you have multiple instances of FTPClient, each with its own thread running inside?

    A: Multiple instances of FTPClient can be used to connect to multiple (or the same) FTP server and concurrently retrieve files. If you want to share a single FTPClient instance between multiple threads, you must serialize access to the object with critical sections.
    *kein Kommentar* Ich habe jetzt eine boolean-Varibable eingeführt, die das Objekt praktisch sperrt. Wäre nur schöner, wenns mit Monitoren ginge, weil das doch eleganter anmutet...

    /EDIT: Jetzt geht's ja doch! RogerJFX, dankeschön Ich war verwirrt, weil das Programm immer noch die NOOP-Ausgabe bringt, aber der Befehl wird nurnoch dann *wirklich* ausgeführt, wenn keine andere Operation mehr läuft. Hmtja, jetzt bin ich aber vollends verwirrt.
    Geändert von Technaton (25-05-2005 um 09:00 Uhr)

  7. #7
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von Technaton
    @anda_skoa: Ohne System.out habe ich keine Möglichkeit, das Programm zu testen -- ich habe keinen Zugriff zu irgendwelchen FTP-Logs. Ist System.out nicht threadsicher?
    Doch, natürlich.
    Darum wäre es eben eine Quelle für ein mögliches Thread Problem.

    Übrigens hast du einige Aufrufe von Methoden am FTP Objekt nicht synchronized.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  8. #8
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    Zitat Zitat von anda_skoa
    Doch, natürlich.
    Darum wäre es eben eine Quelle für ein mögliches Thread Problem.
    Das verstehe ich nicht: Warum ist es der Grund für ein Threadproblem, wenn es doch Threadsicher ist?!

    Übrigens hast du einige Aufrufe von Methoden am FTP Objekt nicht synchronized.
    Ich habe jetzt, wie Roger riet, die ganze run() methode synchronisiert, jetzt geht es. Was mich nur immer noch verwirrt, ist, WARUM es jetzt geht, schließlich sind die FTP-Dinger doch angeblich nicht threadsicher. Nicht, daß ich am Ende irgendwelche Broken Pipes oder sowas habe...

  9. #9
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von Technaton
    Das verstehe ich nicht: Warum ist es der Grund für ein Threadproblem, wenn es doch Threadsicher ist?!
    Weil dann ein weiterer Monitor ins Spiel kommt.

    Ich habe jetzt, wie Roger riet, die ganze run() methode synchronisiert, jetzt geht es.
    Logischerweise weil die beiden Threads die nicht gemeinsam haben und jeder in seinem eigenen Monitor arbeitet

    Was mich nur immer noch verwirrt, ist, WARUM es jetzt geht, schließlich sind die FTP-Dinger doch angeblich nicht threadsicher.
    Zufall, Glück.

    Gegenseitiger Ausschluß ist ja nur nötig, um einen sicheren Zustand zu garantieren, nicht unbedingt nötig um ihn zu haben, das kann auch zufällig passen.

    Ich würde vorschlagen du machst die beiden Klassen nur implements Runnable.
    Dann kannst du eine als extra Thread laufen lassen und eine im Hauptthread und sparst dir beim Testen die join() Hacks.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  10. #10
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    Mit dem Threadkram bin ich immer noch nicht so ganz grün, gnah. Das synchronisieren der run()-Methoden bringt also nullgarnix? Dann doch lieber synchronisierten Zugriff auf eine Boole-Variable, die sozusagen als Sperrer fungiert... Das wird hoffentlich wohl hinhaun.

    Das ganze Listing oben war eh nur ein einziger Test, die Grundidee ist, daß ein Thread dauernd läuft und NOOP sendet, während Einzelnkommandos dann ab und zu einstechen. Ich denke mal, daß ich das mit der Sperrvariable jetzt gelöst bekommen habe...

    Danke euch.

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •