Pertanyaan Bagaimana cara Menghentikan Thread pada suatu titik tertentu?


Saya mencoba menghentikan beberapa benang, membaca beberapa hal tentang cara yang tepat untuk melakukannya dengan anggun, tetapi saya harus melakukan sesuatu yang salah karena itu tidak berhasil. Awalnya saya mencoba tanpa lock() dengan _IsRunning menjadi mudah menguap, lalu mencoba dengan kunci. Ini yang saya punya.

private volatile bool _IsRunning;
private static readonly object runLock = new object();

public void Start()
{
    if (_IsRunning == true)
        return;
    _IsRunning = true;
    (new System.Threading.Thread(new System.Threading.ThreadStart(SendLoop))).Start();
}

public void Stop()
{
    lock (runLock)
    {
        _IsRunning = false;
    }
}

private void SendLoop()
{
    while (_IsRunning)
    {
        lock (runLock)
        {
            if (_sockets.Count > 0)
            {
                //some stuff
            }
            else
            {
                System.Threading.Thread.Sleep(10);
            }
        }
    }
}

Saya menetapkan breakpoint di saya while(), dan _IsRunnig masih benar meskipun saya lulus Stop().


4
2018-03-29 15:28


asal


Jawaban:


Kunci diperlukan di sini karena cara metode awal Anda ditulis, namun Anda hanya perlu kunci Start() (di mana tidak sekarang) dan Stop(), karena merekalah satu-satunya yang berpotensi menyebabkan kondisi balapan dalam kasus Anda.

Saya akan menghapus kunci dari Anda SendLoop() metode sepenuhnya (itu menyebabkan a Jalan buntu sejak Stop sedang menunggu di kunci untuk mengatur _isRunning, dan Anda SendLoop memegang kunci sampai _isRunning diatur ke false). Saat ini, ketika Anda menelepon Stop(), kunci mencegahnya dari yang pernah pengaturan _isRunning = false;

Namun, Anda harus mengunci kunci Anda Start() dan Stop() metode (kecuali Anda mengolah kembali cara mereka terstruktur sepenuhnya). Sesuatu seperti:

public void Start()
{
    lock (runLock)
    {
        if (_IsRunning == true)
            return;
        _IsRunning = true;
        (new System.Threading.Thread(new System.Threading.ThreadStart(SendLoop))).Start();
    }
}

public void Stop()
{
    lock (runLock)
    {
        _IsRunning = false;
    }
}

Ini akan melindungi Anda dari memulai 2 utas, dan juga akan mencegah Stop berhenti sebelum utas dimulai.


5
2018-03-29 16:24



Anda perlu mengatur ulang lingkaran Anda sedikit. Saat ini Anda memegang kunci di runLock untuk waktu yang sangat lama. Ini akan menyebabkan siapa pun memanggil metode Berhenti untuk hang sampai blok if berhasil atau panggilan Sleep kembali. Ini dapat menyebabkan masalah karena Anda tidak dapat melihat _isRunning ketika metode Stop dipanggil, hanya ketika kembali. Coba atur ulang kode Anda sebagai berikut

private void SendLoop() {
  do {
    if ( _sockets.Count > 0 ) {
    } else { 
      System.Threading.Thread.Sleep(10);
    }
    bool shouldContinue;
    lock ( runLock ) { 
      shouldContinue = _IsRunning;
    }
  while(shouldContinue);
}

Saya tidak 100% yakin ini masalahnya. Tapi setidaknya itu akan membantu sedikit menjernihkan.


2
2018-03-29 15:34