Школоло / Говнокод #14442 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
procedure tmythread.execute;
  procedure fillmemo;
  begin
    form1.memo1.lines.add('Some string');
  end;
begin
  synchronize(fillmemo); //[Error] Unit1.pas(54): There is no overloaded version of 'Synchronize' that can be called with these arguments
end;

Почему нельзя сделать вещи, сделанные "через анус", еще более "через анус"?

Запостил: Stertor Stertor, (Updated )

Комментарии (121) RSS

    • Потому что этот код не имеет смысла. Процедура fillmemo имеет доступ к переменным в стеке текущего треда (ну здесь их нет, но если ты поставишь var между строками 1 и 2 - будет). Если ее исполнить в другом потоке, что и делает synchronize, то код просто распидорасит. Как-то так.

      А почему оно не компилится - я х.з. Надо смотреть сигнатуру synchronize'а. Возможно он со спецом не жрет вложенные функции.

      О нормальных лямбдах, которые должны проканать на 2009: http://8vmr.livejournal.com/6114.html

      Реквестирую в тред Тараса, чтобы он меня поправил и обозвал нубом, не знающим делфи.
      Ответить
      • Хах. А если та же процедура возьмет переменную прямо из класса потока, не распидорасит? Один хуй же в другом потоке:
        type
            tmythread=class(tthread)
            private
            sometext:string;
            procedure ololo;
            protected
            procedure execute;override;
            public
          end;
        
          procedure tmyclass.Ololo;
          begin
            showmessage(sometext);
          end;
        
        procedure tmythread.execute;
        begin
          sometext:='Ololo';
          synchronize(ololo);
        end;

        ведь не пидорасит.

        p/s/
        Василий,если Вы здесь,срочно забаньте ботов - форум спамят.
        Ответить
        • > не распидорасит?
          Ну да, резонно. Синхронайз же текущий поток держит в спячке, пока функция до конца не выполнится.

          Тогда попробуй передать @fillmemo вместо fillmemo. Вроде же в паскале так делали указатель на функцию, а fillmemo - ее вызов.

          P.S. Я в делфи реально нуб.
          Ответить
          • Так нельзя. Это в частных редких случаях работает. Это всё равно, что делать:
            ::std::string sometext;
            void thread1(){
              sometext = "thread1";
              ::std::lock_guard(mutex1);
              showmessage(sometext);
            }
            
            void thread2(){
              sometext = "thread2";
              ::std::lock_guard(mutex1);
              showmessage(sometext);
            }
            //...
            ParallelRun(thread1, thread2);
            Вопрос только в том, кто успеет первым?
            Ответить
            • Ну synchronized он все-таки блочит текущий тред пока указанная процедура не доработает. Так что с этим все норм.
              Ответить
              • > synchronized он все-таки блочит текущий тред
                Не важно. Упрощу код для понимания.
                ::std::string sometext;
                void thread1(){
                  sometext = "thread1";
                }
                
                void thread2(){
                  sometext = "thread2";
                }
                //...
                ParallelRun(thread1, thread2).WaitAll();
                print(sometext);
                Что произойдет? UB. Хоть упадет.
                Ответить
                • Возможно, я ошибаюсь, но исходя из моего опыта, мне кажется, что сначала отработает один поток, затем второй. Synchronize() посылает потоку, который держит форму, сообщение о том, чтобы он вызвал метод, указанный в качестве параметра в Synchronize(). Поток, вызвавший Synchronize() будет заблокирован до полного завершения указанного метода. Двойного обращения к объекту не происходит, иначе какой же это Synchronize 😉
                  Ответить
                  • Меня что-то переклинило. Сделал общий sometext для потоков. Такого быть не должно ни если создали поток из локальной функции с замыканием не из класса потока с перегруженным виртуальным методом. Конечно можно создать static член, но это сам себе злобный буратина.
                    Ответить
          • > Тогда попробуй передать @fillmemo вместо fillmemo.

            Нельзя такую хуйню делать. @ это чтобы убрать проверку соответствия процедурных типов с непредсказуемыми последствиями.
            Ответить
        • > procedure tmyclass.Ololo;
          > synchronize(ololo);

          то есть оно таки принимает не процедуру, а делегат
          Ответить
        • >> Один хуй же в другом потоке:

          Это в каком таком потоке я хуй?
          Ответить
      • >А почему оно не компилится
        Не тарас, но потому что старый дельфи не может в замыкания. А вложенная процедура - это таки замыкание (могло бы быть), т.к. имеет доступ к локальным переменным вызвавшей процедуры.
        Разумеется код ниже работает т.к. там нет доступа к локальным переменным, только к полям объекта.
        Ответить
        • Но вложенные процедурки вполне передавались во всякие sort'ы, хоть они и не полноценные замыкания, и дохнут в конце содержащей их функции. Или я туплю?
          Ответить
          • Не передавались. Возможно в каком-то очень старом паскале могли передаваться (т.к. вроде бы по виртовскому стандарту могут), но в дельфи точно нет.

            Насчет дохнут - а как компилятору это разрулить? Молча разрешать брать на них указатель и потом крашиться?
            Ответить
            • Ну да, вроде так и было в борланд паскале, если я конечно не туплю. А может и туплю.
              Ответить
              • Лень качать. Может в турбопаскале и было. Я сам был уверен что можно брать указатели на вложенные процедуры, пока в холиварах не начал участвовать.
                Ответить
                • Нельзя. В Турбопаскале можно было брать указатели только на невложенные функции, причём только с атрибутом far.

                  Для сравнения в gcc чтобы работали указатели на вложенные функции, пришлось делать трамплины. Т. е. в gcc замыкания — это уже не чистые функции, а что-то похожее на методы объектов (хотя в няшной по стандарту ООП нету).

                  В стандартном же Паскале не было процедурного типа, но был тип аргумента procedure, а как там было со вложенными функциями, не знаю. Некоторые реализации стандартного Паскаля компилировались не в нативный код, а в P-code, так что там возможность реализации всяких фишек зависела от виртуальной машины.
                  Ответить
          • > Но вложенные процедурки вполне передавались во всякие sort'ы
            Авотхуй.

            Кстати в Аде передаются, но только если ты скажешь, что sort принимает именно замыкание, а не функцию. Кстати синтаксис описания замыкания в Аде эээ отсутствует. Надо писать
            procedure Sort(in out A : TArray; sorter : access procedure (L,R : T) : boolean);

            И затайпдефнуть эту хрень никакого способа нету!!! И это в Аде, что везде и всегда заставляет каждый чих тайпдефить!!!
            Ответить
            • А хотя я не знаю как было в олдскульном Паскале. Может там тоже изъебнулись как-то. Может кстати через исполняемый стек.
              Ответить
        • У старого Дельфи вместо замыканий есть делегаты, то, до чего ко-ко-ко-кресты до сих пор не дошли.
          Ответить
                • скомпилится?
                  struct ololo
                  {
                    int a;
                    ololo(a):a(a) {}
                    void kokoko(int &i) {i+=a;}
                  };
                  ololo trololo(5);
                  std::function<class void(int&)> f = trololo.kokoko;
                  Ответить
                  • struct ololo {
                      void kokoko(int) {}
                      void kokoko(double) {}
                      static void kokoko(foo) {}
                    };
                    ololo tarasb;
                    tarasb.kokoko  // какой тип у этого выражения?
                    Ответить
                    • Это перпендикулярная проблема. Отделяй мух от котлет.
                      Кстати я в натуре не знаю, как при перегрузке надо звать указатель на функцию, чтобы было однозначно.
                      Ответить
                      • > как при перегрузке надо звать указатель на функцию, чтобы было однозначно

                        Как? Статик каст? Промежуточная переменная?
                        Ответить
                        • Не понял про промежуточную переменную.
                          Ещё можно так:
                          struct T//Обойдусь без всяких длиннющих трололо ололо и кококо
                          {
                            void f(int a){...};//Шеф! Всё пропало. Указатель не взять. 
                            void f(char b){...};
                            template<M> void f(M b){...};
                          };
                          
                          struct B
                          {
                            template<class ST, class M> void operator()(ST this_, M param1){this_->f(param1);}//Можно много перегрузок под разное число параметров.
                          };//Можно генерировать класс под разные методы макросом.
                          
                          T a;
                          function<void (int&)> f = bind(B(), &a _1);
                          bind можно выкинуть, передав &a в конструктор B. Правда чтобы не выводить самому шаблон ST в B - можно написать функцию генератор. B конечно может быть не шаблонным, если случай как здесь достаточно частный.
                          Ответить
                          • > Не понял про промежуточную переменную.
                            int  f(char);
                            long f(double);
                            
                            struct S {
                             int  g(char);
                             long g(double);
                            };
                            
                            int main()
                            {
                                // No ambiguity
                                int (*fc)(char) = f;
                                int (S::*pm)(char) = &S::g;
                                return 0;
                            }
                            Ответить
                            • А если я хочу auto?
                              Почему нельзя написать
                              auto fc = f(char)?
                              Ответить
                              • > Почему нельзя написать
                                Ну почему нельзя? Можно.




                                Только не заработает. Пишите свой язык. Ктож запрещает? Особенно если для себя.
                                Ответить
                    • Как здрово, программист-дальтоник выбирает, за какой шнурок потянуть...
                      Ответить
                  • function<void(int&)> f = bind(&trololo.kokoko, &ololo, _1);
                    function<void(int&)> f = [&](int &i){trololo.kokoko(i);};
                    Что нужно то ещё? Синтаксического сахара? Не нужен.
                    Ответить
                    • Да, молодец, создал проксю, которая хренит оъект и вызывает его метод.
                      КРЕСТОКОСТЫЛЬ
                      Ответить
                  • Но случай явно от лукавого и должен выглядеть так:
                    function<void(int&)> f = [a](int& i){I+=a};
                    Или даже так:
                    //using namespace boost::phoenix::arg_names;
                    function<void(int&)> f = (arg1+=a);
                    Ответить
              • Ай... Сколько раз уже предлагали поменять студию на gcc или новую студию... Сколько раз скидывались на покупку нового компьютера Тарасу...
                Ответить
                • Так я предложил просто послать мне 200к рублей на новый комп, но они стали что-то подозревать и не стали посылать деньги.
                  Ответить
      • Вложенные функции это не функции, а замыкания (иначе никак, не считая сомнительного мудизма с исполняемым стеком).
        Есть такой тип reference to procedure (...), являет собой объект, аллоцирующий в куче то, что он захватил и имеющий виртуальный метод (), управляется по счётчику ссылок. Так вот вложенные функции - это он и есть, ну вернее не он, но может приводиться к нему.
        Ответить
        • Насчет приводится кстати фиг - по логике может и могли бы, но по факту не компилируется.
          Ответить
          • Значит получаем 3й тип замыканий.
            1. Вложенные функции
            2. Делегаты
            3. Собсна замыкания
            Ответить
  • >Почему нельзя сделать вещи, сделанные "через анус", еще более "через анус"?

    "Анус" трескает.
    Ответить
  • ДЕЛФИПРОБЛЕМЫ

    извините, не удержался после беглого прочтения дискуссии
    Ответить
    • Товарищи, безопасен ли этот код (решил тут выложить, чтобы не создавать новую тему):
      unit Unit1;
      
      interface
      
      uses
        Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
        Dialogs, StdCtrls, ExtCtrls;
      
      type
        TForm1 = class(TForm)
          Memo1: TMemo;
          Button1: TButton;
          Button2: TButton;
          Timer1: TTimer;
          procedure Button1Click(Sender: TObject);
          procedure Button2Click(Sender: TObject);
          procedure FormCreate(Sender: TObject);
          procedure Timer1Timer(Sender: TObject);
        private
          { Private declarations }
        public
          { Public declarations }
        end;
      
      var
        Form1: TForm1;
        list:tstringlist;
      
      implementation
      
      {$R *.dfm}
      
      procedure TForm1.Button1Click(Sender: TObject);
      var
        i:integer;
      begin
        for i:=0 to 5000 do
        list.add(inttostr(i));
      
        for i:=0 to list.Count -1 do  // обратите внимание: я не вызываю здесь application.processmessages - это опасно.
        memo1.lines.add(list[i]);
      end;
      
      procedure TForm1.Button2Click(Sender: TObject);  // сначала нажимаем на кнопку, вызывающую заполнение мемо, затем тут же жмем на эту
      var
        I : Integer;
      begin
        list.clear;
      end;
      
      procedure TForm1.FormCreate(Sender: TObject);
      begin
        list:=tstringlist.Create;
      end;
      
      procedure TForm1.Timer1Timer(Sender: TObject);
      begin
        timer1.Enabled:=false;
        while true do
        application.ProcessMessages; {на form.create() цеплять нельзя, форма не покажется.}
      end;
      
      end.


      Цикл заполняет мемо, читая из листа, и тут же рядом цикл крутит processmessages. Не возникнет ли асинхронность, которая вызовет выход за границы?
      Ответить
      • > procedure TForm1.Timer1Timer(Sender: TObject);
        begin
        timer1.Enabled:=false;
        while true do
        application.ProcessMessages; {на form.create() цеплять нельзя, форма не покажется.}
        end;


        ЧТО ЭТО ЗА ХУЙНЯ?!
        Ответить
        • Это я так вызываю application.processmessages, чтобы посмотреть, сможет ли она спровоцировать ошибку - она же асинхронность вызывает. А по таймеру, чтобы лишнюю кнопку не делать. Запускается форма, далее таймер вызывает цикл и останавливается.
          Ответить
          • > она же асинхронность вызывает
            Ты знаешь, что такое асинхронность?
            Твой таймер делает хуйню, вернее он делает то, что программа делает и без него.
            Ответить
            • Я в курсе, кэп. Это ведь не прога. Это просто тестовый быдлокод, призванный прояснить мне назначение application.processmessages.
              Ответить
              • У application.processmessages назначение состоит в том, что когда ты обходишь крутую рекурсивную структуру, то ты можешь не выходя наверх и не сохраняя состояние стека не забывать отдавать пользователю возможность тыкать по кнопочкам, надо всего лишь при обработке каждого узла вызывать "пропихнуть сообщения", и кстати делается это в текущем потоке.
                Ответить
                • обходить рекурсивную структуру лучше в отдельном потоке, посылая сообщения гуйне. В твоем случае надо очень часто и равномерно дергать processmessages, чтобы гуй был отзывчивый.

                  Очередь сообщений имеет смысл дергать при ожидании нужного сообщения или определенный условий. Что-то вроде ожидания семафора(мьютекса) без блокировки потока.
                  Ответить
                  • > В твоем случае надо очень часто и равномерно дергать processmessages, чтобы гуй был отзывчивый.

                    Равномерно не обязательно.

                    > обходить рекурсивную структуру лучше в отдельном потоке

                    Траеблядь штоле?
                    Ответить
                      • Многоядерные процессоры придумали для того, чтобы программы не мешали друг другу, а не для того, чтобы траебляди, не осилившие состояния, траеблядствовали свой траеблядский код, засирая все ядра и вгоняя систему в ступор.
                        Ответить
                        • > три бляди три бляди три бляди
                          типичная краткая история отечественных вокально-инструментальных ансамблей
                          Ответить
                      • дорогие многоядерные процессоры и неэффективные 3д ускорители-печки нужны только анскильным крестушкам, чтобы хотя бы приблизительно имитировать быстродействие, которое на старых надёжных системах достигается профессиональными однопоточными языками
                        Ответить
                    • А если, допустим, есть рекурсивная функция,которая ищет файлы?

                      >>Траеблядь штоле?
                      У Гислера в ТК она однопоточная )
                      Ответить
                      • Мне кажется, что Гитлер был тредоблядью.
                        Потому что Гитлер был плохой и тредоблядство тоже плохо.
                        Ответить
        • Дело вовсе не в таймере.
          procedure TForm1.Button3Click(Sender: TObject);
          begin
          while true do
            application.ProcessMessages;
          end;


          Я хочу узнать, безопасно ли будет нажимать вышеуказанные кнопки, когда где-то рядом крутится processmessages. Если без processmessages, то после нажатия кнопки Button1 форма залочена - юзер физически не сможет нажать на Button2. А с application.processmessages вроде сможет, и это вызовет крах. Или не?
          Ответить
          • Только что проверил. Оказывается, processmessages вызывает обработку сообщений только из того места, где он вызывается. После нажатия Button1 форма все равно будет залочена, несмотря на то, что рядом висит цикл, который вызывает processmessages. Главное, не вызвать тут:
            procedure TForm1.Button1Click(Sender: TObject);
            var
              i:integer;
            begin
              for i:=0 to 5000 do
              list.add(inttostr(i));
            
              for i:=0 to list.Count -1 do
              begin
              memo1.lines.add(list[i]);
              application.processmessages;// форма теперь не залочена, несмотря на цикл, и если юзер вздумает нажать на Button2 - будут проблемы.
              end;
            end;
            
            procedure TForm1.Button2Click(Sender: TObject);  // сначала нажимаем на кнопку, вызывающую заполнение мемо, затем тут же жмем на эту
            var
              I : Integer;
            begin
              list.clear;
            end;
            Ответить
  • Кстати, synchronize запускает в каком-то обособленном потоке? Захватывает мьютекс? Или может в потоке диалога?
    Ответить
        • Где-то выше был уже ответ на этот вопрос: Synchronize отсылает главному потоку сообщение о том, чтобы он вызвал метод, указанный в качестве параметра в Synchronize(), с блокировкой данного потока, до завершения работы метода.
          >>Или может в потоке диалога?
          Если под диалогом подразумевается главная форма, то пожалуй, да.
          Ответить

Добавить комментарий

Помни, guest, за тобой могут следить!

    А не использовать ли нам bbcode?


    8