Синхронизация Kotlin не работает должным образом - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь создать простую программу, которая представляет собой модель броуновского движения с использованием параллелизма (примеси случайным образом перемещаются в клетках влево и вправо).У меня есть классы Примеси и Клетки.Класс ячеек содержит массив ячеек, которые означают, сколько примесей в каждой ячейке в данный момент.Каждый объект нечистоты изменяет массив ячеек в ячейках в собственном потоке.Я запускаю потоки, и они работают в бесконечном цикле в течение 1 секунды.Но до и после этого я печатаю сумму примесей в ячейках, и эти значения не равны, что означает, что я что-то не так делаю с синхронизацией.Вот код:

Класс ячеек:

object Cells {
    var cell = Array(N) { 0 }

    fun addImpurity(impurity: Impurity) {
        cell[impurity.currentCell]++
    }

    @Synchronized
    fun move(impurity: Impurity, direction: Direction) {
            if (direction == Direction.LEFT && impurity.currentCell > 0) {
                cell[impurity.currentCell]--
                cell[impurity.currentCell - 1]++

                impurity.currentCell--
            } else if (direction == Direction.RIGHT && impurity.currentCell < N - 1) {
                cell[impurity.currentCell]--
                cell[impurity.currentCell + 1]++

                impurity.currentCell++
            }
            Unit
    }

    fun printCells() {
        for (c in cell)
            print("$c ")
    }
}

enum class Direction {
    LEFT, RIGHT
}

Класс примесей:

class Impurity(var currentCell: Int) {
    private lateinit var thread: Thread

    init {
        Cells.addImpurity(this)
    }

    fun startMoving() {
        thread = Thread {
            while (true) {
                if (random() > P)
                    Cells.move(this, Direction.RIGHT)
                else
                    Cells.move(this, Direction.LEFT)
            }
        }

        thread.start()

    }

    fun stopMoving() = thread.interrupt()
}

и Main:

const val N = 10
const val K = 15
const val P = 0.5

fun main(args: Array<String>) {
    val impurities = ArrayList<Impurity>()

    for (i in 1..K)
        impurities.add(Impurity(0))

    println(Cells.cell.sum())

    startMoving(impurities)

    Thread.sleep(1000)

    stopMoving(impurities)

    Cells.printCells()

    println(Cells.cell.sum())
}

private fun startMoving(impurities: ArrayList<Impurity>) {
    for (impurity in impurities)
        impurity.startMoving()
}

private fun stopMoving(impurities: ArrayList<Impurity>) {
    for (impurity in impurities)
        impurity.stopMoving()
}

Заранее спасибо!

1 Ответ

0 голосов
/ 11 декабря 2018

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

class Impurity(var currentCell: Int) {
    ...
    private var _continue = true

    fun startMoving() {
        thread = Thread {
            while (_continue) {
        }
    }

    ...

    fun stopMoving() {
        _continue = false
    }
}

Кроме того, вы можете также подождать, пока сам поток не умрет, как часть вызова на stopMoving.Это гарантирует, что все потоки определенно получили сигнал и выйдут из своих циклов, прежде чем вы вызовете Cells.printCells.Например, вы можете добавить этот метод в класс Impurity:

fun waitForEnded() = thread.join()

И вы можете обновить stopMoving в основном классе, чтобы вызывать этот метод после подачи сигнала каждому потоку об остановке:

private fun stopMoving(impurities: ArrayList<Impurity>) {
    for (impurity in impurities)
        impurity.stopMoving()
    impurities.forEach(Impurity::waitForEnded)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...