2013-06-23 6 views
1

У меня возникла небольшая проблема с простым приложением для копирования файлов, которое я пишу в Visual Basic 2005. У меня есть основной поток, который отслеживает графический интерфейс и сканирование файлов/копирования я создал отдельный поток, который я создаю так:Visual Basic, Child Thread Blocking Main Thread

trd_copy = New Thread(AddressOf CopyTask) 
    trd_copy.IsBackground = True 
    trd_copy.Start() 

Это прекрасно работает на этапе сканирования операции, и я могу использовать кнопки в графическом интерфейсе просто отлично. Проблема заключается в том, что, когда CopyTask переходит на фазу копирования файлов (используя File.Copy), основной поток, как представляется, блокируется, и графический интерфейс с ним, что означает, что кнопка, которую я имею там для прерывания операции копирования, бесполезна. Когда копирование завершено, все возвращается в нормальное состояние, а во время копирования вспомогательный поток может обновить строку состояния в основной форме.

Уверен, что я пропустил что-то простое, но я не могу, чтобы жизнь меня видела, что это такое.

Большое спасибо!

Edit: Добавление кода для CopyTask():

Private Sub CopyTask() 
    Control.CheckForIllegalCrossThreadCalls = False 
    If check_scanfirst.Checked Then 
     status1.Text = "Scanning..." 
     bytestocopy = 0 
     scandir(src) 

     filesscanned = True 
     MsgBox("Scanning completed") 
    End If 

    If check_delete.Checked Then 
     ' Do a clean of the destination, removing any files that don't exist in the source dir 
    End If 

    If filesscanned Then 
     ProgressBar1.Visible = True 
     ProgressBar1.Minimum = 0 
     ProgressBar1.Maximum = 100 
     ProgressBar1.Refresh() 
    End If 

    checkdir(src) 
    MsgBox("Copying completed") 
    If filesfailed > 0 Then 
     MsgBox("Warning: " + Str(filesfailed) + " files were not copied successfully.") 
    End If 
    guistop() 
End Sub 
+1

Хм .. код для CopyTask? –

+0

Вы случайно используете 'Invoke()' в 'CopyTask()'? Распространенная ошибка заключается в том, чтобы вызвать весь метод, таким образом, отрицая создание потока в первую очередь ... –

+0

Извините, должен был добавить его - сейчас это главный вопрос. Не использовать Invoke вообще. Я относительно новичок в этом, исходя из кода прошивки/базового фона Blitz, поэтому я только изучаю ... Как я уже сказал, часть scandir() работает, как и ожидалось, реагирует и обновляется. checkdir() - это точно такой же код, только добавляет вызов File.Copy на каждую итерацию. – Daedalus

ответ

1

Из того, что я могу сказать, все вызовы к системе также GUI Thread основе независимо от того, если вы хотите их или нет. И Control.CheckForIllegalCrossThreadCalls = False очень плохо, вы всегда хотите написать свой поток и (если начинаете) запускать код, и каждый раз, когда он вырывается из кода, чтобы написать делегат и функцию вызова для этой части вашего потока (занимая больше всего минимальное время) можно в потоке Gui (Main).

Вот пример с полным исходный код

http://www.codeproject.com/Articles/15104/Multithreading-with-VB-NET-A-beginner-s-choice

в вашей теме

Control.CheckForIllegalCrossThreadCalls = False - это нужно удалена Если check_scanfirst.Checked Тогда - это нужен делегат и метод вызова status1.Text = «Сканирование ...» - для этого нужен делегат и метод вызова bytestocopy = 0 ScanDir (ЦСИ) - если ScanDir (есть призывы к графическому интерфейсу), это требует делегата и вызов метода, но внутри ScanDir()

filesscanned = True 
    MsgBox("Scanning completed")    -- this needs a delegate and invoke method (keep in mind thread will keep running even if mesgbox not clicked) 
End If 

If check_delete.Checked Then    -- this needs a delegate and invoke method 
    ' Do a clean of the destination, removing any files that don't exist in the source dir 
End If 

If filesscanned Then 
    ProgressBar1.Visible = True    -- this needs a delegate and invoke method 
    ProgressBar1.Minimum = 0    -- this needs a delegate and invoke method 
    ProgressBar1.Maximum = 100    -- this needs a delegate and invoke method 
    ProgressBar1.Refresh()    -- this needs a delegate and invoke method 
End If 

checkdir(src) 
MsgBox("Copying completed")    -- this needs a delegate and invoke method 
If filesfailed > 0 Then 
    MsgBox("Warning: " + Str(filesfailed) + " files were not copied successfully.")    -- this needs a delegate and invoke method 
End If 
guistop()    -- this needs a delegate and invoke method if (guistop makes calls to gui) 

так что если вы не можете сказать, вашим делая много призывает к гую ... вот как я бы написать это сделать очень просто

, как я хотел бы написать свой код (это написал в слове какой-то код может понадобиться подправить)

Private sub DoStuffBeforeCopy() 
If check_scanfirst.Checked Then 
    status1.Text = "Scanning..." 
    bytestocopy = 0 
trd_copy.ParameterizedStart(src) //start thread 
end sub 

CopyTask(byval src as *string*?) 
    scandir(src) – put the code here or make another thread (src is better) 
    filesscanned = True 

    invoke-MsgBox("Scanning completed") 

    invoke If check_delete.Checked Then 

    If filesscanned Then 
     Invoke-ProgressBar1.Visible = True 
     Invoke-ProgressBar1.Minimum = 0 
     Invoke-ProgressBar1.Maximum = 100 
     Invoke-ProgressBar1.Refresh() 
    End If 

    checkdir(src) – put the code here or make another thread (src is better) 

    invoke-MsgBox("Copying completed") 

    If filesfailed > 0 Then 
     Invoke-MsgBox("Warning: " + Str(filesfailed) + " files were not copied successfully.") 
    End If 

    guistop()– put the code here or make another thread (src is better) 

End sub 

* * СДЕЛАТЬ ЭТО ДЛЯ ЛЮБОГО Delegat/Invoke необходимого

для потоков вызовов с параметрами

trd_copy.ParameterizedStart (ЦСИ)

Delegate Sub nameofDelegate(s As Integer) 
Sub nameofDelegate+NameofSub(ByVal s As Integer) 
    If Form1.ProgressBar1.InvokeRequired Then 
     Dim d As New nameofDelegate (AddressOf nameofDelegate+NameofSub) 
     NameOfYourForm.Invoke(d, New Object() {s}) 
    Else 
     If s = 1 Then 
      NameOfYourForm.ProgressBar1.Refresh() ** Or other Gui Functions 
     Else 

     End If 
    End If 
End Sub 

Для Thread вызовов без parametrs

trd_copy.Start()

Delegate Sub nameofDelegate() 
Sub nameofDelegate+NameofSub() 
    If Form1.ProgressBar1.InvokeRequired Then 
     Dim d As New nameofDelegate (AddressOf nameofDelegate+NameofSub) 
     NameOfYourForm.Invoke(d, New Object()) 
    Else 
     NameOfYourForm.ProgressBar1.Refresh() ** Or other Gui Functions 
    End If 
End Sub 
+0

Большое спасибо Pakk, я попробую завтра вечером и дам вам знать, как я нахожусь. Это немного имеет смысл, но я до сих пор не понимаю, зачем мне делегировать такие вещи, как MsgBox - я хочу, чтобы они блокировались, они действительно существуют только для отладки. Scandir() работает точно так, как ожидалось, и является рекурсивным, поэтому я не могу поместить туда код, и я не понимаю, зачем ему нужен другой поток. Аналогично для checkdir. Я ожидал, что, поскольку код CopyTask был отдельным потоком, подпрограммы scandir() и checkdir() также запускались в потоке CopyTask. – Daedalus

+0

Приветствуем вас, вы хотите делегатов, потому что вы хотите как минимум поддерживать взаимодействие с основным потоком, поэтому вызов будет стоить вам 1 мс взаимодействия (подвешивает его надолго) и весь поток до того, как долго он длится , Msgbox вам действительно не нужно, когда он был выпущен (если там только там для отладки, в котором я их оставил), я все равно рекомендую Scandir() находиться внутри потока (только если он не делает UI-вызовы - в противном случае очень много вызовов делегировать/вызывать), но всякий раз надеюсь, что это сработает для вас – Pakk

+0

Итак, что вы подразумеваете под потоком? Если он вызван из потока, разве это не часть этого потока? Я не могу поместить код непосредственно в CopyTask, так как он рекурсивный - он вызывает себя для каждого каталога, который встречается в пути «src», поэтому это просто частный суб. Scandir() не имеет системных вызовов и работает нормально, но checkdir() имеет файл File.Copy, который, если я его прокомментирую, работает вокруг проблемы. Таким образом, похоже, что это, как вы говорите, системные вызовы, которые утомляют его. Я сообщу позже. Еще раз спасибо :) – Daedalus