2009-05-25 11 views
1

Actuellement, j'ai quelque chose comme:classe OpenNETCF FTP question multithreading

public partial class Form1 : Form 
{ 
delegate void StringDelegate(string value); 

private FTP m_ftp; 

public Form1() 
{ 
InitializeComponent(); 
} 

private void connect_Click(object sender, EventArgs e) 
{ 
OnResponse("Connecting"); 
m_ftp = new FTP(server.Text); 
m_ftp.ResponseReceived += new FTPResponseHandler(m_ftp_ResponseReceived); 
m_ftp.Connected += new FTPConnectedHandler(m_ftp_Connected); 
m_ftp.BeginConnect(user.Text, password.Text); 
} 

void m_ftp_Connected(FTP source) 
{ 
// when this happens we're ready to send command 
OnResponse("Connected."); 
} 

void m_ftp_ResponseReceived(FTP source, FTPResponse Response) 
{ 
OnResponse(Response.Text); 
} 

private void OnResponse(string response) 
{ 
if (this.InvokeRequired) 
{ 
this.Invoke(new StringDelegate(OnResponse), new object[] { response }); 
return; 
} 

} 

private void getFileList_Click(object sender, EventArgs e) 
{ 
FTPFiles files = m_ftp.EnumFiles(); 

fileList.Items.Clear(); 

foreach (FTPFile file in files) 
{ 
fileList.Items.Add(new ListViewItem(new string[] { file.Name, file.Size.ToString() })); 
} 

tabs.SelectedIndex = 1; 
} 

private void upload_Click(object sender, EventArgs e) 
{ 
FileStream stream = File.OpenRead("\\My Documents\\My Pictures\\Waterfall.jpg"); 
m_ftp.SendFile(stream, "waterfall.jpg"); 
stream.Close(); 
} 

Ce qui fonctionne très bien - cet exemple a été prise à partir des échantillons. Cependant, après une récente visite, j'ai une question. Dans ce cas particulier, puisque la fonction OnResponse() ne met pas à jour l'interface utilisateur, elle ne semble pas utile ici. Je l'ai supprimé (ainsi que tous les appels à celui-ci) et il fonctionne toujours comme avant. Est-ce que je manque quelque chose? Après avoir lu plus sur le multi thread avec des formulaires, j'ai fini par comprendre que ce mécanisme (démontré dans le code ci-dessus) est là pour s'assurer que l'interface utilisateur est réactive.

Donc, dans le cas où nous devons dire, mettre à jour un élément d'interface utilisateur (comme zone de texte, l'étiquette, etc.), nous aurions OnResponse mis en œuvre comme suit:

delegate void StringDelegate(string dummy); 
void OnResponse(string dummy) 
{ 
    if(!InvokeRequired) 
    { 
     button1.Text = dummy; 
    } 
    else 
     Invoke(new StringDelegate(OnResponse),new object[] {enabled}); 
} 

Si cette fonction est implémentée comme:

delegate void StringDelegate(string dummy); 
    void OnResponse(string dummy) 
    { 
     if(InvokeRequired) 
     {    
      Invoke(new StringDelegate(OnResponse),new object[] {dummy}); 
      return; 
     } 
    } 

Quelle est l'utilité de l'avoir? Est-ce absolument nécessaire?

Et une autre question: l'objet ftp s'exécute-t-il sur son propre thread ici?

Répondre

1

L'objet FTP fonctionne définitivement sur son propre thread. Comment puis-je savoir? Cette ligne:

m_ftp.BeginConnect(user.Text, password.Text); 

Ceci est une méthode asynchrone. Une fois que vous l'appelez, le composant FTP utilisera un thread du pool de threads .NET pour effectuer tout le travail. Ce fil dédié est celui qui est utilisé pour "élever" les événements. En fin de compte, un «événement surélevé» est juste un ou plusieurs appels de méthode à tous les délégués ajoutés à la liste d'invocation d'événement; c'est ce thread dédié qui est dérivé de la méthode Begin qui appelle ces méthodes. Ce thread n'est pas le même thread que le thread qui exécute l'interface utilisateur, d'où la nécessité des appels Invoke.

Si vous souhaitez que le composant FTP utilise le thread d'interface utilisateur, vous devez utiliser la méthode Connect à la place de la méthode BeginConnect. Cela signifie que vos événements ne fonctionneront pas non plus, et votre interface utilisateur ne répondra pas à l'interaction - ceci est totalement attendu car un thread ne peut faire qu'une seule chose à la fois: soit gérer l'interface utilisateur, soit exécuter le code FTP. C'est pourquoi vous avez besoin d'un 2ème thread.

Avez-vous du sens?

-Oisin

+0

Merci! sorta fait. Le code actuel peut mettre à jour l'interface utilisateur à l'intérieur de m_ftp_ResponseReceived() ... C'est pourquoi je suis confus. Ma compréhension était que l'objet FTP était en cours d'exécution dans son propre fil, mais je ne devrais pas être en mesure de mettre à jour l'interface utilisateur dans m_ftp_ResponseReceived() sauf si j'utilise Invoke. Ce qui donne? Je voudrais continuer à utiliser le BeginConnect() car je veux que l'interface utilisateur soit réactive. – sarsnake

+0

également s'il vous plaît noter que OpenNetCF n'a pas de méthode Connect dans la classe FTP, seulement BeginConnect() – sarsnake

+0

Je viens de le tester plus, et il semble que je suis capable de mettre à jour l'interface utilisateur de m_ftp_ResponseReceived(). mais IMPOSSIBLE de le faire depuis m_ftp_Connected(). Toute une observation intéressante. m_ftp_Connected doit être exécuté sur le thread de l'interface utilisateur. – sarsnake