Потоки в C# (критика)

kokoc88

Вот такой код умирает в дедлоке:
 
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
namespace DelAbort
{
    class Program
    {
     static TextWriter stdOut = System.Console.Out;
     object locker = new object;
     void Run
     {
     Thread t = new Thread(new ThreadStart(delegate
     {
     try
     {
     Thread.Sleep(500);
     }
     finally
     {
     lock (locker)
     {
     Thread.Sleep(2000);
     stdOut.WriteLine("Thread has finished its finally.");
     }
     }
     };
     t.IsBackground = false;
     t.Start;
     lock (locker)
     {
     Thread.Sleep(1000);
     t.Abort;
     stdOut.WriteLine("Main thread has exit.");
     }
     }
     static void Main(string[] args)
     {
     new Program.Run;
     System.Console.In.Read;
     }
    }
}
  

bleyman

Что именно тебя удивляет?

kokoc88

Что именно тебя удивляет?
То, что я написал. Что этот код умирает с дедлоком.

bleyman

Можешь ещё написать финалайзер, в котором тоже что-нибудь залочЪ. Вот будет удивительно! Или ещё можно в финалайзерах выкидывать объект из очереди на удаление, тоже мазёвая штука.
Или тебя удивляет, что в одном случае стоит Wait(500 а в другом Wait(1000 а всё равно случается дедлок?

kokoc88

Можешь ещё написать финалайзер, в котором тоже что-нибудь залочЪ. Вот будет удивительно! Или ещё можно в финалайзерах выкидывать объект из очереди на удаление, тоже мазёвая штука.
Или тебя удивляет, что в одном случае стоит Wait(500 а в другом Wait(1000 а всё равно случается дедлок?
Блядь. Нет. Меня ничто не удивляет, но я считаю такое поведение серьёзной ошибкой проектирования языка и потоковых библиотек. Ты хотя бы посмотрел, ГДЕ и КАК повисают оба потока или пиздишь без дела, являясь любителем C#? Кстати, в Java подобный код не повиснет.

Helga87

Когда ты вызываешь Abort, поток висит в lock, т.е. на самом деле в unmanaged code, т.к. в .net средства синхронизации есть лишь обертка над соответствующими средствами windows. В справке к Thread.Abort сказано:
Thread.Abort Method
Raises a ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the thread. Calling this method usually terminates the thread.
...
The thread is not guaranteed to abort immediately, or at all. This situation can occur if a thread does an unbounded amount of computation in the finally blocks that are called as part of the abort procedure, thereby indefinitely delaying the abort.
...
If, while executing unmanaged code, a thread ignores a ThreadAbortException, the system re-throws the ThreadAbortException when the thread begins executing managed code.

Особенно внимательно стоит прочесть третий абзац.
Такое поведение не является "хорошим", но оно является документированным и таково "by design". В результате, Microsoft не рекомендует использовать Thread.Abort.

kokoc88

Когда ты вызываешь Abort, поток висит в lock, т.е. на самом деле в unmanaged code
Да, да, со всем этим разобрались. Документацию почитали. Пост только о том, что прерывание потоков сделано криво.

Helga87

Ну дык.
С потоками в .net и еще одна задница есть: если в потоке не из ThreadPool возникает неотловленное исключение, валится весь домен.

daru

Пост только о том, что прерывание потоков сделано криво.

Оно везде сделано криво (имеется в виду насильственное прерывание типа Thread.Abort): и в posix, и в win32, наверное и в jav'е не без косяков. Очень сложно сделать это прямо, если вообще возможно. Вряд ли стоило рассчитывать, что .net будет являться исключением из правила.

kokoc88

и в jav'е не без косяков
В Java как раз без косяков.

Helga87

как решена проблема по типу:
try
{
чо-то делаем с файлом
}
finally
{
чо-то поделали,
закрываем файл
}

Поток начал абортиться, когда исполнение вошло в finally, но еще не дошло до закрытия файла. Вопрос: что будет с файлом? Он так и будет незакрыт?

otets-mihail

GC вызовет finalize для соответствующего файлу объекта и там файл закроется?

Helga87

время исполнения finalizer-а конечно недетерминировано, при наличии достаточного количества памяти это может произойти, скажем, через полчаса, да? что в это время будут делать другие желающие поюзать этот файл? есть предположение, что либо прибьют процесс, либо как-то специально ручками вызовут GC

kokoc88

Поток начал абортиться, когда исполнение вошло в finally, но еще не дошло до закрытия файла. Вопрос: что будет с файлом? Он так и будет незакрыт?
Нет, всё будет в порядке. Поток прерывается, после чего исключение выкидывается только в ждущих функциях. Которые в finally на уровне языка заставят включить в try/catch блоки, т.к. они throws InterruptedException.

Helga87

Еще раз: у нас исполнялся finally, выбросился ThreadAbortedException (или как там аналог называется и мы пролетели мимо закрытия файла.
Или тут есть отличие между .net и Java? Если да, то можно подробно описать поведение программы при Abort-е Thread-а?

otets-mihail

Отличие, наверное, в том, что InterruptedException может возникнуть не везде, а только в особых функциях, типа sleep/waitFor/...

kokoc88

Еще раз: у нас исполнялся finally, выбросился ThreadAbortedException (или как там аналог называется и мы пролетели мимо закрытия файла.
Или тут есть отличие между .net и Java? Если да, то можно подробно описать поведение программы при Abort-е Thread-а?
finally {
try {
actionsWhichThrowInterruptedException;
}
catch (InterruptedException e) {
}
file.close;
}

Видишь, тебе синтаксически не дадут просто так вызвать функции, которые викидывают InterruptedException. От тебя потребуют try/catch или спецификации исключения. Thread.interrupt просто ставит потоку флаг. После чего этот флаг можно либо проверить руками, либо вызов следующей ждущей функции сразу же кинет InterruptedException, либо уже выполняющаяся ждущая функция выкинет InterruptedException.

Helga87

т.е. получается, что если у меня в потоке есть бесконечный цикл while (true) {}, который находится в функции без декларации возможности выброса InterruptedException, то поток никак нельзя будет убить?

kokoc88

т.е. получается, что если у меня в потоке есть бесконечный цикл while (true) {}, который находится в функции без декларации возможности выброса InterruptedException, то поток никак нельзя будет убить?
Есть функции грубого останова, которые очень не рекомендуется использовать. Но я не вижу в отсутствии способа остановить такой поток ничего плохого.

Helga87

о, это хорошо. Более удобно, чем в .net. Хотя, видимо к функции грубого останова все те же минусы, что и к .net-овскому Abort применимы.

kokoc88

Хотя, видимо к функции грубого останова все те же минусы, что и к .net-овскому Abort применимы
Конечно, применимы. Но эти минусы очень плохие, хуже чем в C#.
Оставить комментарий
Имя или ник:
Комментарий: