Беспорядок Поточной обработки/Блокировки C#

Существует много сообщений, жалующихся на перегрузку оператора.

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

запутывание Кода?

Этим аргументом является ошибка.

Запутывание возможно на всех языках...

столь же легко запутать код в C или Java через функции/методы, как это находится в C++ посредством перегрузок оператора:

// C++
T operator + (const T & a, const T & b) // add ?
{
   T c ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

// Java
static T add (T a, T b) // add ?
{
   T c = new T() ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

/* C */
T add (T a, T b) /* add ? */
{
   T c ;
   c.value = a.value - b.value ; /* subtract !!! */
   return c ;
}

... Даже в стандартных интерфейсах Java

Для другого примера, давайте посмотрим Cloneable интерфейс в Java:

Вы, как предполагается, клонируете объект, реализовывая этот интерфейс. Но Вы могли лгать. И создайте другой объект. На самом деле этот интерфейс так слаб, Вы могли возвратить другой тип объекта в целом, просто ради удовольствия:

class MySincereHandShake implements Cloneable
{
    public Object clone()
    {
       return new MyVengefulKickInYourHead() ;
    }
}

Как эти Cloneable интерфейс может быть оскорблен/запутан, он должен быть запрещен на том же основании, перегрузка оператора C++, как предполагается?

Мы могли перегрузиться toString() метод MyComplexNumber, класс, чтобы иметь его возвращает stringified час дня. toString() перегрузка должна быть запрещена, также? Мы могли саботировать MyComplexNumber.equals, чтобы иметь его, возвращают случайное значение, изменяют операнды... и т.д. и т.д. и т.д.

В Java, как в C++, или безотносительно языка, программист должен уважать минимум семантики когда написание кода. Это означает реализовывать add функция, которая добавляет, и Cloneable метод внедрения, который клонируется, и ++ оператор, чем инкременты.

, Что запутывает так или иначе?

Теперь, когда мы знаем, что код может саботироваться даже через нетронутые методы Java, мы можем спросить нас о реальном использовании оператора, перегружающегося в C++?

Четкая и естественная нотация: методы по сравнению с перегрузкой оператора?

Мы выдержим сравнение ниже, для различных случаев, "того же" кода в Java и C++, чтобы иметь идею, от которой вид стиля кодирования более свободен.

Естественные сравнения:

// C++ comparison for built-ins and user-defined types
bool    isEqual          = A == B ;
bool    isNotEqual       = A != B ;
bool    isLesser         = A <  B ;
bool    isLesserOrEqual  = A <= B ;

// Java comparison for user-defined types
boolean isEqual          = A.equals(B) ;
boolean isNotEqual       = ! A.equals(B) ;
boolean isLesser         = A.comparesTo(B) < 0 ;
boolean isLesserOrEqual  = A.comparesTo(B) <= 0 ;

Обратите внимание на то, что A и B мог иметь любой тип в C++, пока перегрузки оператора обеспечиваются. В Java, когда A и B не являются примитивами, код может стать очень сбивающим с толку, даже для подобных примитиву объектов (BigInteger, и т.д.)...

Естественные средства доступа массива/контейнера и индексирование:

// C++ container accessors, more natural
value        = myArray[25] ;         // subscript operator
value        = myVector[25] ;        // subscript operator
value        = myString[25] ;        // subscript operator
value        = myMap["25"] ;         // subscript operator
myArray[25]  = value ;               // subscript operator
myVector[25] = value ;               // subscript operator
myString[25] = value ;               // subscript operator
myMap["25"]  = value ;               // subscript operator

// Java container accessors, each one has its special notation
value        = myArray[25] ;         // subscript operator
value        = myVector.get(25) ;    // method get
value        = myString.charAt(25) ; // method charAt
value        = myMap.get("25") ;     // method get
myArray[25]  = value ;               // subscript operator
myVector.set(25, value) ;            // method set
myMap.put("25", value) ;             // method put

В Java, мы видим, что, чтобы каждый контейнер сделал то же самое (получают доступ к его содержанию через индекс или идентификатор), у нас есть различный способ сделать это, который сбивает с толку.

В C++, каждый контейнер использует тот же способ получить доступ к его содержанию благодаря перегрузке оператора.

Естественное усовершенствованное управление типами

примеры ниже используют Matrix объект, найденный использованием первых ссылок, найденных на Google для" объект Матрицы Java " и" объект Матрицы C++ ":

// C++ YMatrix matrix implementation on CodeProject
// http://www.codeproject.com/KB/architecture/ymatrix.aspx
// A, B, C, D, E, F are Matrix objects;
E =  A * (B / 2) ;
E += (A - B) * (C + D) ;
F =  E ;                  // deep copy of the matrix

// Java JAMA matrix implementation (seriously...)
// http://math.nist.gov/javanumerics/jama/doc/
// A, B, C, D, E, F are Matrix objects;
E = A.times(B.times(0.5)) ;
E.plusEquals(A.minus(B).times(C.plus(D))) ;
F = E.copy() ;            // deep copy of the matrix

И это не ограничено матрицами. BigInteger и BigDecimal классы Java страдают от того же запутывающего многословия, тогда как их эквиваленты в C++ так же ясны как встроенные типы.

Естественные итераторы:

// C++ Random Access iterators
++it ;                  // move to the next item
--it ;                  // move to the previous item
it += 5 ;               // move to the next 5th item (random access)
value = *it ;           // gets the value of the current item
*it = 3.1415 ;          // sets the value 3.1415 to the current item
(*it).foo() ;           // call method foo() of the current item

// Java ListIterator "bi-directional" iterators
value = it.next() ;     // move to the next item & return the value
value = it.previous() ; // move to the previous item & return the value
it.set(3.1415) ;        // sets the value 3.1415 to the current item

Естественные функторы:

// C++ Functors
myFunctorObject("Hello World", 42) ;

// Java Functors ???
myFunctorObject.execute("Hello World", 42) ;

текстовая конкатенация:

// C++ stream handling (with the << operator)
                    stringStream   << "Hello " << 25 << " World" ;
                    fileStream     << "Hello " << 25 << " World" ;
                    outputStream   << "Hello " << 25 << " World" ;
                    networkStream  << "Hello " << 25 << " World" ;
anythingThatOverloadsShiftOperator << "Hello " << 25 << " World" ;

// Java concatenation
myStringBuffer.append("Hello ").append(25).append(" World") ;

хорошо, в Java можно использовать MyString = "Hello " + 25 + " World" ; также... Но, ожидайте секунда: Это - перегрузка оператора, не так ли? Разве это не обман???

:-D

Общий код?

тот же общий код, изменяющий операнды, должен быть применимым оба для built-ins/primitives (которые не имеют никаких интерфейсов в Java), стандартные объекты (который не мог иметь правильного интерфейса), и пользовательские объекты.

, Например, вычисляя среднее значение двух значений произвольных типов:

// C++ primitive/advanced types
template
T getAverage(const T & p_lhs, const T & p_rhs)
{
   return (p_lhs + p_rhs) / 2 ;
}

int     intValue     = getAverage(25, 42) ;
double  doubleValue  = getAverage(25.25, 42.42) ;
complex complexValue = getAverage(cA, cB) ; // cA, cB are complex
Matrix  matrixValue  = getAverage(mA, mB) ; // mA, mB are Matrix

// Java primitive/advanced types
// It won't really work in Java, even with generics. Sorry.

оператор Discussing, перегружающийся

Теперь, когда мы видели справедливые сравнения между перегрузкой оператора использования кода C++ и тем же кодом в Java, мы можем теперь обсудить "оператор, перегружающийся" как понятие.

перегрузка Оператора существовала еще до компьютеров

Даже за пределами информатики, существует перегрузка оператора: Например, в математике, операторы как [1 122], -, *, и т.д. перегружаются.

Действительно, значение [1 125], -, *, и т.д. изменяется в зависимости от типов операндов (численные данные, векторы, квантовые волновые функции, матрицы, и т.д.).

Большинство из нас, как часть наших научных курсов, изучило несколько значений для операторов, в зависимости от типов операндов. Мы находили их сбивающими с толку, их?

перегрузка Оператора зависит от своих операндов

, Это - самая важная часть перегрузки оператора: Как в математике, или в физике, операция зависит от типов своих операндов.

Так, знайте тип операнда, и Вы будете знать эффект операции.

Даже C и Java (трудно кодировали) оператор, перегружающийся

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

В Java, нет никакой адресной арифметики с указателями, но кто-то все еще нашел конкатенацию строк без +, оператор будет достаточно смешон выровнять по ширине исключение в "перегрузке оператора, злое" кредо.

Это просто, что Вы, как C (по историческим причинам) или Java (для [1 195] личные мотивы , видят ниже), кодер, Вы не можете обеспечить свое собственное.

В C++, перегрузка оператора не является дополнительной...

В C++, оператор, перегружающийся для встроенных типов, не возможен (и это - хорошая вещь), но пользовательский , типы могут иметь пользовательский перегрузки оператора.

, Как уже сказано ранее, в C++, и об обратном к Java, пользовательские типы не считают второразрядными гражданами языка, по сравнению со встроенными типами. Так, если встроенные типы имеют операторы, пользовательские типы должны смочь иметь их, также.

истина - то, что, как toString(), clone(), equals() методы для Java ( т.е. квазиподобный стандарту ), перегрузка оператора C++ является таким большим количеством части C++, что это становится столь же естественным как исходные операторы C, или перед упомянутыми методами Java.

Объединенный с шаблонным программированием, перегрузка оператора становится известным шаблоном разработки. На самом деле Вы не можете пойти очень далеко в STL, не используя перегруженные операторы, и перегрузив операторы для Вашего собственного класса.

..., но этим нельзя злоупотребить

, перегрузка Оператора должна стремиться уважать семантику оператора. Не вычитайте в + оператор (поскольку в "не вычитают в add, функция", или "возвращают дерьмо в clone метод").

перегрузка Броска может быть очень опасной, потому что они могут привести к неоднозначностям. Таким образом, они должны действительно быть зарезервированы для четко определенных случаев. Что касается [1 135] и ||, никогда не перегружайте их, если Вы действительно не знаете то, что Вы делаете, поскольку Вы потеряете оценку короткого замыкания, которой обладают собственные операторы && и ||.

Так... Хорошо... Затем, почему это не возможно в Java?

, поскольку James Gosling сказал так:

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

James Gosling. Источник: http://www.gotw.ca/publications/c_family_interview.htm

сравните текст Gosling выше с Stroustrup ниже:

Много проектных решений C++ имеют свои корни в моей неприязни к тому, чтобы вынуждать людей делать вещи некоторым конкретным способом [...] Часто, я испытал желание запретить функцию, которую я лично не любил, я воздержался от выполнения поэтому, потому что я не думал, что имел право вызвать мои представления о других .

Bjarne Stroustrup. Источник: Desing и Эволюция C++ (1.3 Общих Фона)

оператор Would, перегружающий Java преимущества?

Некоторые объекты значительно извлекли бы выгоду из перегрузки оператора (конкретные или числовые типы, как BigDecimal, комплексные числа, матрицы, контейнеры, итераторы, компараторы, синтаксические анализаторы и т.д.).

В C++, можно получить прибыль от этого преимущества из-за смирения Stroustrup. В Java Вы просто завинчены из-за Gosling личный выбор .

это могло быть добавлено к Java?

причинами того, что не был добавлен оператор, перегружающийся теперь в Java, могло быть соединение внутренней политики, аллергии на функцию, недоверие к разработчикам (Вы знаете, саботажника, которые, кажется, преследуют команды Java...), совместимость с предыдущим JVMs, время для записи корректной спецификации, и т.д.

Так не задерживают Ваше дыхание, ожидающее этой функции...

, Но они делают это в C#!!!

Да...

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

, По-видимому, люди C#, с их "каждый примитив struct, и struct происходит из Объекта" , разобрался в нем при первой попытке.

И они делают это в [1 145] другие языки !!!

Несмотря на весь FUD против используемой определенной перегрузки оператора, следующие языки поддерживают его: Scala, Dart, Python , F# , C#, D, Алгол 68 , Smalltalk, Groovy, Perl 6, C++, Ruby, Haskell, MATLAB, Eiffel, Lua, Clojure, Фортран 90 , Swift, Ada, Delphi 2005 ...

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

Пища для размышления...

6
задан Scott Klarenbach 14 August 2009 в 23:50
поделиться

3 ответа

В следующем примечании из документации MSDN на ThreadPool сказано все:

Потоки в пуле управляемых потоков являются фоновыми потоками. То есть их свойства IsBackground истинны. Это означает, что поток ThreadPool не будет поддерживать работу приложения после выхода всех потоков переднего плана .

Ваше приложение просто завершает работу (по достижении конца Main ) до того, как ваши потоки закончат работу.

9
ответ дан 9 December 2019 в 22:38
поделиться

Как насчет коротких и сладких?

    static int wrkThreads = 0;
    static readonly EventWaitHandle exit = new ManualResetEvent(false);
    static readonly object syncLock = new object();

    static void Main( string[] items )
    {
        wrkThreads = items.Length;

        foreach ( var item in items )
            ThreadPool.QueueUserWorkItem(( DoWork ), item);

        exit.WaitOne();
    }

    static void DoWork( object obj )
    {
        lock ( syncLock ) {
            /* Do your file work here */
        }
        if ( Interlocked.Decrement(ref wrkThreads) == 0 )
            exit.Set();
    }
0
ответ дан 9 December 2019 в 22:38
поделиться

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

class Program
{
    static void Main(string[] args)
    {
        var items = new string[] { "1", "2", "3", "300" };
        using (var outfile = File.AppendText("file.txt"))
        {
            using (var ws = new WorkSet<string>(x =>
                    { lock (outfile) outfile.WriteLine(x); }))
                foreach (var item in items)
                    ws.Process(item);
        }
    }

    public class WorkSet<T> : IDisposable
    {
        #region Interface

        public WorkSet(Action<T> action)
        { _action = action; }

        public void Process(T item)
        {
            Interlocked.Increment(ref _workItems);
            ThreadPool.QueueUserWorkItem(o =>
                    { try { _action((T)o); } finally { Done(); } }, item);
        }

        #endregion
        #region Advanced
        public bool Done()
        {
            if (Interlocked.Decrement(ref _workItems) != 0)
                return false;

            _finished.Set();
            return true;
        }

        public ManualResetEvent Finished
        { get { return _finished; } }

        #endregion
        #region IDisposable

        public void Dispose()
        {
            Done();
            _finished.WaitOne();
        }

        #endregion
        #region Fields

        readonly Action<T> _action;
        readonly ManualResetEvent _finished = new ManualResetEvent(false);
        int _workItems = 1;

        #endregion
    }
}
2
ответ дан 9 December 2019 в 22:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: