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

У меня есть проблема с многопоточностью и концептуальный вопрос с использованием Visual Basic (но это относится почти ко всем языкам). У меня есть функция, которая:

  1. создает 5 экземпляров класса, каждый из которых порождает поток, вызывающий функцию
  2. Функция спит в течение X миллисекунд
  3. выводит на консоль
  4. затем завершает поток

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

Наиболее актуальная помощь в исследованиях: как сделать паузу main(), пока все остальные потоки не прекратятся?

Вот мой код:

Imports System
Imports System.Threading
Imports System.Collections.Generic
Module Module1
    Private raceTrack As New List(Of RaceCar)
    Sub Main()
        CreateRace() 
        'Main() would quit when the 5 car objects are created =[
        'How do I make sure Main will not exit until all racecars are done?
    End Sub

    Sub CreateRace()
        For index As Integer = 1 to 5
            raceTrack.Add(new RaceCar(index))
        Next
    End Sub

    Public Class RaceCar
        Private testThread as Thread =  New Thread(AddressOf StartEngine)
        Private carId as Integer
        Public Sub New(ByVal carNumber as Integer)
            me.carId = carNumber
            Me.TestThread.Start()
            Me.TestThread.Join()
        End Sub

        Public Sub StartEngine()
            Console.WriteLine(String.Format("Car#{0} is going!", Me.carId))
            Thread.Sleep(100*Me.carId)
            Console.WriteLine(String.Format("Car#{0} is DONE!", Me.carId))
        End Sub

    End Class

End Module

2 ответа

Решение

Видимо твой RaceCar конструктор возвращает только когда законченный порожденный поток, так как вы вызываете Join,

    Public Sub New(ByVal carNumber as Integer)
        me.carId = carNumber
        Me.TestThread.Start()
        Me.TestThread.Join()
    End Sub

Я не знаю, является ли это намеренным (скорее всего, нет, потому что вы создаете свой RaceCar экземпляры в цикле, так что у вас нет параллелизма, поскольку следующий экземпляр не может быть создан до тех пор, пока не вернется предыдущий вызов конструктора), но ваш основной поток не может завершиться, пока не завершатся все дочерние потоки.

Я предлагаю следующую реструктуризацию:

Удалить Join от конструктора и добавьте новый метод в ваш RaceCar учебный класс:

Public Sub JoinThread()
    Me.TestThread.Join()
End Sub

Теперь цикл создания объекта не будет блокироваться. Добавьте еще один цикл потом:

Sub CreateRace()
    For index As Integer = 1 to 5
        raceTrack.Add(new RaceCar(index))
    Next

    // other work maybe?

    For Each car As RaceCar In raceTrack
        car.JoinThread()
    Next
End Sub

Теперь ваши потоки будут запускаться в первом цикле, работать параллельно и, в конце концов, остановятся на новом "барьерном цикле".

Обратите внимание, что основной поток все еще может выполнять другие задачи между двумя циклами.

(Отказ от ответственности: я никогда не программировал на vb.net, так что, надеюсь, то, что я написал, не совсем неправильно.)

Я не уверен, что что-то упустил (держу пари, это пример проекта), но не могу воспроизвести проблему. Я вижу все машины, которые приходят, когда я запускаю код, который вы опубликовали (за исключением вызова.Join, как упомянуто Тудором).

Но если я установлю Thread.IsBackground в Trueтогда я вижу твою проблему. Чтобы убедиться, что ваш Threads заканчивают перед Process завершается, сделайте это:

Public Sub New(ByVal carNumber As Integer)
    Me.carId = carNumber
    Me.testThread.IsBackground = False ' <--This will cause threads to be 'Foreground'
    Me.testThread.Start()
End Sub

Взгляните на определение Thread.IsBackground: http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.95).aspx

Это свойство сообщает вам, Process будет ждать Thread закончить, прежде чем прекратить. Очевидно, в вашем случае, вы хотите, чтобы это было False, По умолчанию False во многих случаях, но могут быть случаи, когда для него установлено значение true.

Другие вопросы по тегам