Неоднозначная ситуация с функцией преобразования в классе

Тема в разделе "LANGS.C", создана пользователем Ronin_, 2 июн 2017.

  1. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    ОК. Давайте логически рассуждать. shared_ptr - по сути, объект, хранящий внутри указатель + счётчик ссылок. Чтобы правильно собрать мусор, то есть удалить объект, на который ссылается указатель, нужно хранить где-то информацию о том, сколько объектов типа shared_ptr ссылаются на "автоматический" объект. Иными словами, где-то надо хранить счётчик, на который будут ссылаться все объекты типа shared_ptr, которые хранят указатель на один и тот же "автоматический" объект. Получаем дополнительное выделение памяти на хипе, что, по сути, уже подразумевает проседание производительности, так как эту память надо выделять. Ну и ещё можете std::bad_alloc схватить.
    Двигаемся дальше, переходим в multithreaded-среду. Пускай два shared_ptr'а одновременно удаляются в двух потоках, количество ссылок на "автоматический" объект также равно двум. И происходит это всё на двух разных процессорах. Имеем, что надо одновременно вычесть из shared-блока два раза по единице, убедиться, что счётчик ссылок обнулился, и удалить "автоматический" объект. По сути это реализуется на atomic'ах (наверное, я не совсем корректно сказал про "блокировки", но, по сути, это оно и есть), что и видно в приведённом мною примере. Atomic'и работают раз в 10 медленнее обычных инструкций доступа к памяти, имеем сильное проседание по производительности.

    Так что двойка вам.

    Читаем выше до просветления.

    Я так не считаю в отличие от плюсоидов, привыкших возводить C++ в абсолют.

    Разные, но я предполагаю, что не обрабатываете в принципе, раз начали настолько издалека.

    А о чём говорить? Сильно фрагментированная память - попытались создать std::string большой длины - упали по std::bad_alloc.
    Не поймали исключение - вывалились из main. Приложуха упала, крантец. И плевать, что приложуха, например, управляет регулированием охлаждения ТВЭЛов на атомной станции.

    И тратится куча времени на написание никому ненужного кода, который будет юзаться в одном месте. Вы, наверное, решили потягаться с китайскими коллегами в объёмах?

    Это нифига не специальный случай. Это достаточно частый случай, когда вы работаете с несколькими ресурсами одновременно, каждый из которых может практически на любой инструкции зафейлить по тому же I/O, например (кто-то тупо выдернет сетевой кабель, например). И никакой RAII вас тут не спасёт, потому что RAII подразумевает порядок уничтожения, обратный порядку объявления. А тут выясняется, что уничтожать, вроде бы, надо и не всё, и как бы не всегда, и даже не во всех случаях.

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

    При чём тут java? Вы напишите функцию, которая последовательно открывает первый, второй и третий файлы, что-то с ними делает (при этом учитывает, что любая операция ввода-вывода может зафейлить), а затем закрывает первый и третий файлы, а хэндл на второй возвращает как результат. Ну и попробуйте это всё провернуть на RAII. Думаю, день мозготраха обеспечен. А в C-стиле это всё делается элегантно и лаконично.

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

    То ли дело, можно невозбранно скармливать null operator'у delete.

    А вы не подумали, что в finally можно делать ещё какую-то полезную работу кроме как финализировать объект?

    Бред.
     
  2. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    Да нет, если бы ты некорректно сказал, ты бы поправился ещё в предыдущем сообщении. Но ты бросился копипастить мне код с блокировками, чем подтвердил, что ты считал, что при изменениях shared_ptr-а они постоянно захватываются.

    Утверждать, что атомики это по сути спин-блокировки может только полный нуль в многопоточном программировании.

    Ха-ха-ха-ха. В общем, про "постоянно дёргающиеся при изменении shared_ptr спинлоки" ты соврал так же, как про UB при исключении в деструкторах. И теперь убого пытаешь делать вид, что это не ты, а я облажался.

    Могу сказать только, что, в общем, как работает shared_ptr изнутри, не знаем, а говно в вентилятор типа "при попытке изменить shared_ptr в multithreaded-среде вы постоянно будете дёргать спин-блокировки" вбрасываем. "Поздравляю тебя, Шарик, ты балбес" (C).

    GC, конечно же, абсолютно бесплатен.

    Ну не хочешь — не надо.

    Приложухи, управляющие ТВЭЛами, в принципе не выделяют память в процессе работы.
    Но размеры раздутости твоего самомнения я заценил.

    Абсолютно то же самое относится к блоку finally.

    Да. А вот с finally запилить аналог RAII гораздо неудобнее. Пришлось try-with-resources вводить, а то жизнь от написания простыней из try-finally совсем несладкой была.

    Что тут сложного? Возвращаем хэндл (RAII-обёртку над ним, хотя бы в виде unique_ptr с кастомным делитером) из функции. Вызывается конструктор перемещения (или вообще происходит copy elision) и владение хэндлом переходит к вызывающему коду, а два остальных хэндла закрываются.

    Ха-ха-ха-ха. Эти жалкие попытки сделать вид, что не облажался.

    Ну да, можно. К чему ты это сейчас написал?

    Я в процитированном тобою сообщении что-то писал про то, что в finally нельзя делать ничего, кроме как финализировать объект?

    Да-да. Как скажешь.
     
  3. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    Прямо заговор мирового правительства. Кто из стоящих насмерть уже пал смертью храбрых под натиском разработчиков, которым смерть как не хватает finally и они круглые сутки осаждают комитет стандартизации?
     
  4. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    А если кто-то тупо жахнет кувалдой по системному блоку? Как эту проблему решает finally?
     
  5. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    В общем, главное, что выяснили, что там атомики, а не спинлоки.
     
  6. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Эк вас понесло, вижу за самое живое задело. Ну ок, давайте по порядку.

    А. ну, то есть, вот этот цикл:
    Код (C):
    1.  
    2.   template<>
    3.     inline bool
    4.     _Sp_counted_base<_S_atomic>::
    5.     _M_add_ref_lock_nothrow()
    6.     {
    7.       // Perform lock-free add-if-not-zero operation.
    8.       _Atomic_word __count = _M_get_use_count();
    9.       do
    10.         {
    11.           if (__count == 0)
    12.             return false;
    13.           // Replace the current counter value with the old value + 1, as
    14.           // long as it's not changed meanwhile.
    15.         }
    16.       while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
    17.                                           true, __ATOMIC_ACQ_REL,
    18.                                           __ATOMIC_RELAXED));
    19.       return true;
    20.     }
    21.  
    Вы к спин-локам не относите? Ну феерично, что. Многопоточник вы наш.

    Ну а как ещё реализуются спин-локи, если не на атомиках? Ну-ка просвятите.

    вы хоть название метода прочитали? _M_add_ref_lock_nothrow(). Как вы думаете, в каком случае будет вызываться этот метод?

    Это и есть UB, когда вы используете third-party библиотеки, где не задокументировано, какие методы какие исключения могут генерировать. А учитывая то, что практически любой метод из STL потенциально может кинуть std::bad_alloc, это вдвойне опасно.

    Ну так вы ж не знаете и набрасываете тут.

    А при чём тут GC? Речь шла о предсказуемости работы компилятора и стандартной библиотеки. А тут не знаешь, сколько раз хип и где дёрнется, и по какому поводу.

    И где тут самомнение? Писать код, который не будет падать от первого чиха и не будет засирать и портить heap, уже считается зазорным?


    Да что вы всё упёрлись в RAII? Нет в Java RAII, потому что основной ресурс - память - удаляется автоматически. А все остальные ресурсы можно освобождать в management-режиме. В плюсах же всё требуют освобождать в автоматическом режиме, назидая этот самый ненавистный RAII. Почему я не могу освобождать некоторые ресурсы в management-режиме? Почему разработчики стандарта компилятора считают, что они намного умнее других людей?

    О, и кастомные делитеры тут внезапно откуда-то взялись. Замечательно, блеск. Отличный способ стимулировать работодателя нанимать ещё несколько разработчиков С++, чтобы те успевали писать лишний код.

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

    К тому, что в нормальных языках это как бы считается ошибкой и надо недопускать ситуаций, когда на удаление уходит указатель/ссылка на несуществующий объект. Но С++ не для обычных людей же.
     
  7. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    Да ты и сам прекрасно можешь найти, где вызываются _M_add_ref_lock и _M_add_ref_lock_nothrow. Никаким "при попытке изменить shared_ptr вы постоянно будете дёргать спин-блокировки" там не пахнет. А "при попытке изменить shared_ptr" вызывается _M_add_ref_copy, где atomic_add, а не спинлок.

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

    Да ты много чего не знаешь, не только это.

    Кто требует? Освобождай как хочешь.

    Ты меня спрашиваешь?

    Облажался — попытайся перейти на личности, называя фанатиком, плюсистом или как ещё ты весь тред пытешься меня задеть
     
  8. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    ОК, в таких ситуациях я прибегаю к дизассемблированию.
    Давайте сделаем простой тест. Напишем пару фунций и глянем на то, что вышло в итоге.
    Код (C):
    1.  
    2. #include <memory>
    3.  
    4. using namespace std;
    5.  
    6. void some_method(shared_ptr<int> &x)
    7. {
    8.   *x = 20;
    9. }
    10.  
    11. void some_func(shared_ptr<int> &x)
    12. {
    13.   shared_ptr<int> y(x);
    14.   some_method(y);
    15. }
    16.  
    17. void some_func2(shared_ptr<int> &x)
    18. {
    19.   shared_ptr<int> y(new int(1));
    20.   x = y;
    21. }
    22.  
    23. int main()
    24. {
    25.   shared_ptr<int> sptr(new int(0));
    26.   some_func(sptr);
    27.  
    28.   return 0;
    29. }
    30.  
    31.  
    Компиляем вот так:
    Код (Text):
    1.  
    2. g++ -lpthread -O2 --std=c++11 main.cpp
    3. objdump -D a.out >a.lst
    4.  
    Ну и смотрим дизасм функций.
    Как и ожидалось, при присвоении значения указателю, который оборачивает shared_ptr, особо ничего криминального не происходит: Просто тупо копирование с двойным разыменованием указателя:
    Код (ASM):
    1.  
    2. 0000000000400af0 <_Z11some_methodRSt10shared_ptrIiE>:
    3.   400af0:   48 8b 07     mov  (%rdi),%rax
    4.   400af3:   c7 00 14 00 00 00     movl  $0x14,(%rax)
    5.   400af9:   c3     retq  
    6.   400afa:   66 0f 1f 44 00 00     nopw  0x0(%rax,%rax,1)
    7.  
     
  9. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Теперь посмотрим, как конструируется наш shared_ptr в some_func:
    Код (ASM):
    1.  
    2. 0000000000400b00 <_Z9some_funcRSt10shared_ptrIiE>:
    3.   400b00:  55  push  %rbp
    4.   400b01:  53  push  %rbx
    5.   400b02:  48 83 ec 08  sub  $0x8,%rsp
    6.   400b06:  48 8b 5f 08  mov  0x8(%rdi),%rbx
    7.   400b0a:  48 8b 17  mov  (%rdi),%rdx
    8.   400b0d:  48 85 db  test  %rbx,%rbx
    9.   400b10:  74 36  je  400b48 <_Z9some_funcRSt10shared_ptrIiE+0x48>
    10.   400b12:  bd 10 09 40 00  mov  $0x400910,%ebp
    11.   400b17:  48 8d 43 08  lea  0x8(%rbx),%rax
    12.   400b1b:  48 85 ed  test  %rbp,%rbp
    13.   400b1e:  74 6c  je  400b8c <_Z9some_funcRSt10shared_ptrIiE+0x8c>
    14.   400b20:  f0 83 00 01  lock addl $0x1,(%rax)
    15.   400b24:  c7 02 14 00 00 00  movl  $0x14,(%rdx)
    16.   400b2a:  ba ff ff ff ff  mov  $0xffffffff,%edx
    17.   400b2f:  f0 0f c1 10  lock xadd %edx,(%rax)
    18.   400b33:  89 d0  mov  %edx,%eax
    19.   400b35:  83 f8 01  cmp  $0x1,%eax
    20.   400b38:  74 1e  je  400b58 <_Z9some_funcRSt10shared_ptrIiE+0x58>
    21.   400b3a:  48 83 c4 08  add  $0x8,%rsp
    22.   400b3e:  5b  pop  %rbx
    23.   400b3f:  5d  pop  %rbp
    24.   400b40:  c3  retq  
    25.   400b41:  0f 1f 80 00 00 00 00  nopl  0x0(%rax)
    26.   400b48:  c7 02 14 00 00 00  movl  $0x14,(%rdx)
    27.   400b4e:  48 83 c4 08  add  $0x8,%rsp
    28.   400b52:  5b  pop  %rbx
    29.   400b53:  5d  pop  %rbp
    30.   400b54:  c3  retq  
    31.   400b55:  0f 1f 00  nopl  (%rax)
    32.   400b58:  48 8b 03  mov  (%rbx),%rax
    33.   400b5b:  48 89 df  mov  %rbx,%rdi
    34.   400b5e:  ff 50 10  callq  *0x10(%rax)
    35.   400b61:  48 85 ed  test  %rbp,%rbp
    36.   400b64:  48 8d 43 0c  lea  0xc(%rbx),%rax
    37.   400b68:  74 37  je  400ba1 <_Z9some_funcRSt10shared_ptrIiE+0xa1>
    38.   400b6a:  ba ff ff ff ff  mov  $0xffffffff,%edx
    39.   400b6f:  f0 0f c1 10  lock xadd %edx,(%rax)
    40.   400b73:  89 d0  mov  %edx,%eax
    41.   400b75:  83 f8 01  cmp  $0x1,%eax
    42.   400b78:  75 c0  jne  400b3a <_Z9some_funcRSt10shared_ptrIiE+0x3a>
    43.   400b7a:  48 8b 03  mov  (%rbx),%rax
    44.   400b7d:  48 89 df  mov  %rbx,%rdi
    45.   400b80:  48 8b 40 18  mov  0x18(%rax),%rax
    46.   400b84:  48 83 c4 08  add  $0x8,%rsp
    47.   400b88:  5b  pop  %rbx
    48.   400b89:  5d  pop  %rbp
    49.   400b8a:  ff e0  jmpq  *%rax
    50.   400b8c:  83 43 08 01  addl  $0x1,0x8(%rbx)
    51.   400b90:  c7 02 14 00 00 00  movl  $0x14,(%rdx)
    52.   400b96:  8b 43 08  mov  0x8(%rbx),%eax
    53.   400b99:  8d 50 ff  lea  -0x1(%rax),%edx
    54.   400b9c:  89 53 08  mov  %edx,0x8(%rbx)
    55.   400b9f:  eb 94  jmp  400b35 <_Z9some_funcRSt10shared_ptrIiE+0x35>
    56.   400ba1:  8b 43 0c  mov  0xc(%rbx),%eax
    57.   400ba4:  8d 50 ff  lea  -0x1(%rax),%edx
    58.   400ba7:  89 53 0c  mov  %edx,0xc(%rbx)
    59.   400baa:  eb c9  jmp  400b75 <_Z9some_funcRSt10shared_ptrIiE+0x75>
    60.   400bac:  0f 1f 40 00  nopl  0x0(%rax)
    61.  
    Вот тут ваши спин-блокировки и поползли. lock xadd в нескольких местах и conditional jump'ы назад по коду.
     
  10. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Ну и добиваем всю эту феерию методом some_func2, который меняет shared_ptr:
    Код (ASM):
    1.  
    2. 0000000000400bb0 <_Z10some_func2RSt10shared_ptrIiE>:
    3.   400bb0:  41 56  push  %r14
    4.   400bb2:  41 55  push  %r13
    5.   400bb4:  41 54  push  %r12
    6.   400bb6:  55  push  %rbp
    7.   400bb7:  48 89 fd  mov  %rdi,%rbp
    8.   400bba:  bf 04 00 00 00  mov  $0x4,%edi
    9.   400bbf:  53  push  %rbx
    10.   400bc0:  e8 7b fd ff ff  callq  400940 <_Znwm@plt>
    11.   400bc5:  bf 18 00 00 00  mov  $0x18,%edi
    12.   400bca:  c7 00 01 00 00 00  movl  $0x1,(%rax)
    13.   400bd0:  49 89 c4  mov  %rax,%r12
    14.   400bd3:  e8 68 fd ff ff  callq  400940 <_Znwm@plt>
    15.   400bd8:  48 3b 45 08  cmp  0x8(%rbp),%rax
    16.   400bdc:  4c 89 60 10  mov  %r12,0x10(%rax)
    17.   400be0:  48 89 c3  mov  %rax,%rbx
    18.   400be3:  c7 40 08 01 00 00 00  movl  $0x1,0x8(%rax)
    19.   400bea:  c7 40 0c 01 00 00 00  movl  $0x1,0xc(%rax)
    20.   400bf1:  41 bd 10 09 40 00  mov  $0x400910,%r13d
    21.   400bf7:  48 c7 00 50 10 40 00  movq  $0x401050,(%rax)
    22.   400bfe:  4c 89 65 00  mov  %r12,0x0(%rbp)
    23.   400c02:  4c 8d 60 08  lea  0x8(%rax),%r12
    24.   400c06:  74 39  je  400c41 <_Z10some_func2RSt10shared_ptrIiE+0x91>
    25.   400c08:  4d 85 ed  test  %r13,%r13
    26.   400c0b:  0f 84 db 00 00 00  je  400cec <_Z10some_func2RSt10shared_ptrIiE+0x13c>
    27.   400c11:  f0 41 83 04 24 01  lock addl $0x1,(%r12)
    28.   400c17:  4c 8b 75 08  mov  0x8(%rbp),%r14
    29.   400c1b:  4d 85 f6  test  %r14,%r14
    30.   400c1e:  74 1d  je  400c3d <_Z10some_func2RSt10shared_ptrIiE+0x8d>
    31.   400c20:  4d 85 ed  test  %r13,%r13
    32.   400c23:  49 8d 46 08  lea  0x8(%r14),%rax
    33.   400c27:  0f 84 af 00 00 00  je  400cdc <_Z10some_func2RSt10shared_ptrIiE+0x12c>
    34.   400c2d:  ba ff ff ff ff  mov  $0xffffffff,%edx
    35.   400c32:  f0 0f c1 10  lock xadd %edx,(%rax)
    36.   400c36:  89 d0  mov  %edx,%eax
    37.   400c38:  83 f8 01  cmp  $0x1,%eax
    38.   400c3b:  74 6b  je  400ca8 <_Z10some_func2RSt10shared_ptrIiE+0xf8>
    39.   400c3d:  48 89 5d 08  mov  %rbx,0x8(%rbp)
    40.   400c41:  4d 85 ed  test  %r13,%r13
    41.   400c44:  0f 84 ae 00 00 00  je  400cf8 <_Z10some_func2RSt10shared_ptrIiE+0x148>
    42.   400c4a:  b8 ff ff ff ff  mov  $0xffffffff,%eax
    43.   400c4f:  f0 41 0f c1 04 24  lock xadd %eax,(%r12)
    44.   400c55:  83 f8 01  cmp  $0x1,%eax
    45.   400c58:  74 0e  je  400c68 <_Z10some_func2RSt10shared_ptrIiE+0xb8>
    46.   400c5a:  5b  pop  %rbx
    47.   400c5b:  5d  pop  %rbp
    48.   400c5c:  41 5c  pop  %r12
    49.   400c5e:  41 5d  pop  %r13
    50.   400c60:  41 5e  pop  %r14
    51.   400c62:  c3  retq  
    52.   400c63:  0f 1f 44 00 00  nopl  0x0(%rax,%rax,1)
    53.   400c68:  48 8b 03  mov  (%rbx),%rax
    54.   400c6b:  48 89 df  mov  %rbx,%rdi
    55.   400c6e:  ff 50 10  callq  *0x10(%rax)
    56.   400c71:  4d 85 ed  test  %r13,%r13
    57.   400c74:  48 8d 43 0c  lea  0xc(%rbx),%rax
    58.   400c78:  0f 84 88 00 00 00  je  400d06 <_Z10some_func2RSt10shared_ptrIiE+0x156>
    59.   400c7e:  ba ff ff ff ff  mov  $0xffffffff,%edx
    60.   400c83:  f0 0f c1 10  lock xadd %edx,(%rax)
    61.   400c87:  89 d0  mov  %edx,%eax
    62.   400c89:  83 f8 01  cmp  $0x1,%eax
    63.   400c8c:  75 cc  jne  400c5a <_Z10some_func2RSt10shared_ptrIiE+0xaa>
    64.   400c8e:  48 8b 03  mov  (%rbx),%rax
    65.   400c91:  48 89 df  mov  %rbx,%rdi
    66.   400c94:  5b  pop  %rbx
    67.   400c95:  5d  pop  %rbp
    68.   400c96:  41 5c  pop  %r12
    69.   400c98:  41 5d  pop  %r13
    70.   400c9a:  41 5e  pop  %r14
    71.   400c9c:  48 8b 40 18  mov  0x18(%rax),%rax
    72.   400ca0:  ff e0  jmpq  *%rax
    73.   400ca2:  66 0f 1f 44 00 00  nopw  0x0(%rax,%rax,1)
    74.   400ca8:  49 8b 06  mov  (%r14),%rax
    75.   400cab:  4c 89 f7  mov  %r14,%rdi
    76.   400cae:  ff 50 10  callq  *0x10(%rax)
    77.   400cb1:  4d 85 ed  test  %r13,%r13
    78.   400cb4:  49 8d 46 0c  lea  0xc(%r14),%rax
    79.   400cb8:  74 6f  je  400d29 <_Z10some_func2RSt10shared_ptrIiE+0x179>
    80.   400cba:  ba ff ff ff ff  mov  $0xffffffff,%edx
    81.   400cbf:  f0 0f c1 10  lock xadd %edx,(%rax)
    82.   400cc3:  89 d0  mov  %edx,%eax
    83.   400cc5:  83 f8 01  cmp  $0x1,%eax
    84.   400cc8:  0f 85 6f ff ff ff  jne  400c3d <_Z10some_func2RSt10shared_ptrIiE+0x8d>
    85.   400cce:  49 8b 06  mov  (%r14),%rax
    86.   400cd1:  4c 89 f7  mov  %r14,%rdi
    87.   400cd4:  ff 50 18  callq  *0x18(%rax)
    88.   400cd7:  e9 61 ff ff ff  jmpq  400c3d <_Z10some_func2RSt10shared_ptrIiE+0x8d>
    89.   400cdc:  41 8b 46 08  mov  0x8(%r14),%eax
    90.   400ce0:  8d 50 ff  lea  -0x1(%rax),%edx
    91.   400ce3:  41 89 56 08  mov  %edx,0x8(%r14)
    92.   400ce7:  e9 4c ff ff ff  jmpq  400c38 <_Z10some_func2RSt10shared_ptrIiE+0x88>
    93.   400cec:  c7 40 08 02 00 00 00  movl  $0x2,0x8(%rax)
    94.   400cf3:  e9 1f ff ff ff  jmpq  400c17 <_Z10some_func2RSt10shared_ptrIiE+0x67>
    95.   400cf8:  8b 43 08  mov  0x8(%rbx),%8(%rbx)
    96.   400d01:  e9 4f ff ff ff  jmpq  400c55 <_Z10some_func2RSt10shared_ptrIiE+0xa5>
    97.   400d06:  8b 43 0c  mov  0xc(%rbeax
    98.   400cfb:  8d 50 ff  lea  -0x1(%rax),%edx
    99.   400cfe:  89 53 08  mov  %edx,0xx),%eax
    100.   400d09:  8d 50 ff  lea  -0x1(%rax),%edx
    101.   400d0c:  89 53 0c  mov  %edx,0xc(%rbx)
    102.   400d0f:  e9 75 ff ff ff  jmpq  400c89 <_Z10some_func2RSt10shared_ptrIiE+0xd9>
    103.   400d14:  48 89 c7  mov  %rax,%rdi
    104.   400d17:  e8 04 fc ff ff  callq  400920 <__cxa_begin_catch@plt>
    105.   400d1c:  4c 89 e7  mov  %r12,%rdi
    106.   400d1f:  e8 9c fb ff ff  callq  4008c0 <_ZdlPv@plt>
    107.   400d24:  e8 a7 fb ff ff  callq  4008d0 <__cxa_rethrow@plt>
    108.   400d29:  41 8b 46 0c  mov  0xc(%r14),%eax
    109.   400d2d:  8d 50 ff  lea  -0x1(%rax),%edx
    110.   400d30:  41 89 56 0c  mov  %edx,0xc(%r14)
    111.   400d34:  eb 8f  jmp  400cc5 <_Z10some_func2RSt10shared_ptrIiE+0x115>
    112.   400d36:  48 89 c3  mov  %rax,%rbx
    113.   400d39:  e8 c2 fb ff ff  callq  400900 <__cxa_end_catch@plt>
    114.   400d3e:  48 89 df  mov  %rbx,%rdi
    115.   400d41:  e8 0a fc ff ff  callq  400950 <_Unwind_Resume@plt>
    116.   400d46:  66 2e 0f 1f 84 00 00  nopw  %cs:0x0(%rax,%rax,1)
    117.   400d4d:  00 00 00
    118.  
    Всё, клиническая картина ясна и масштаб бедствия вполне ощутим. Ну и скорость работы сего решения немного предсказуема.

    Мне кажется, на этом спор можно спокойно закрывать, потому как даже если:
    Тем не менее, я прав, и дизасм это подтвердил.

    Нет, облажались, как раз-таки, вы. Смотрите дизасм выше.
     
  11. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    "Такие ситуации" — это ситуации когда ты вякнул, что при попытке изменить shared_ptr будут постоянно дёргаться спинлоки, а эти спинлоки, как оказывается после более тщательного поиска мест вызовов _M_add_ref_lock[_nothrow], не дёргаются при попытке изменить shared_ptr?

    Да, только давай мы будем смотреть не на неотформатированную ###### в виде помеси мнемокодов с машкодом, а посмотрим на аккуратный код с именованными метками.

    Код (ASM):
    1.  
    2. some_func(std::shared_ptr<int>&):
    3.         push    rbx
    4.         mov     rbx, QWORD PTR [rdi+8]
    5.         mov     rdx, QWORD PTR [rdi]
    6.         test    rbx, rbx
    7.         je      .L9
    8.         mov     eax, OFFSET FLAT:__gthrw___pthread_key_create(unsigned int*, void (*)(void*))
    9.         test    rax, rax
    10.         je      .L10
    11.         lea     rax, [rbx+8]
    12.         lock add        DWORD PTR [rax], 1
    13.         mov     DWORD PTR [rdx], 20
    14.         lock sub        DWORD PTR [rax], 1
    15.         je      .L17
    16. .L8:
    17.         pop     rbx
    18.         ret
    19. .L10:
    20.         add     DWORD PTR [rbx+8], 1
    21.         mov     DWORD PTR [rdx], 20
    22.         mov     eax, DWORD PTR [rbx+8]
    23.         lea     edx, [rax-1]
    24.         cmp     eax, 1
    25.         mov     DWORD PTR [rbx+8], edx
    26.         jne     .L8
    27.         mov     rax, QWORD PTR [rbx]
    28.         mov     rdi, rbx
    29.         call    [QWORD PTR [rax+16]]
    30.         mov     eax, DWORD PTR [rbx+12]
    31.         lea     edx, [rax-1]
    32.         mov     DWORD PTR [rbx+12], edx
    33.         jmp     .L15
    34. .L9:
    35.         mov     DWORD PTR [rdx], 20
    36.         pop     rbx
    37.         ret
    38. .L17:
    39.         mov     rax, QWORD PTR [rbx]
    40.         mov     rdi, rbx
    41.         call    [QWORD PTR [rax+16]]
    42.         mov     eax, -1
    43.         lock xadd       DWORD PTR [rbx+12], eax
    44. .L15:
    45.         cmp     eax, 1
    46.         jne     .L8
    47.         mov     rax, QWORD PTR [rbx]
    48.         mov     rdi, rbx
    49.         pop     rbx
    50.         mov     rax, QWORD PTR [rax+24]
    51.         jmp     rax
    52.  
    Сейчас мы это проверим.
    Ну это пока не спин-блокировка, а только атомарное сложение. Идём дальше:
    Да, есть пара conditional jump-ов назад, на метку .L8, в которой происходит ... возврат из функции!

    Итак, спинлоки не обнаружены.

    — пациенту везде мерещатся спинлоки.

    Естественно, т.к. это специально максимально неоптимально написанный бессмысленный код.

    Вот тут я АБСОЛЮТНО согласен. Т.к.


    Да-да, как выспишься — посмотри ещё раз дизасм выше. Может, спинлокофобия пройдёт.


    В общем, удачи в постижении C++. Приятно было пообщаться.
     
    Последнее редактирование модератором: 16 июл 2017
  12. DelAlt

    DelAlt Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    62
    CurryHowardIsomorphism,
    хочу для себя поинтересоваться: что вы ели, кроме плюсов и в каких объемах? а то складывается впечатление, что некто SadKo ужа давно и неправда, и небезосновательно остановился на лаконичном "чем меньше, тем лучше". а вот с вами история какая-то иная.

    SadKo,
    кстати, да, интересно... а где там спинлоки?(:
     
  13. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    Ну что я ел кроме плюсов можно попробовать догадаться по моему нику.

    Не совсем понял, что тут написано. Особенно в первом предложении.
     
    Последнее редактирование: 10 июл 2017
  14. DelAlt

    DelAlt Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    62
    > Ну что я ел кроме плюсов можно попробовать догадаться по моему нику.
    Матчасть с функиональщиной из вас читалась еще до никнейма, по комплексу превосходства.

    > Не совсем понял, что тут написано. Особенно в первом предложении.
    Сожалею
     
  15. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Моя невиноуатый что редактор так форматирует копипасту с табуляцией. Зря вы "##### обзываетесь".

    А атомарное сложение у нас работает, как раз, на порядок медленнее. Всё, что с явным или неявным lock, работает медленнее.
    Атомарное сложение на ячейке памяти, которая, по сути, и есть объект спин-блокировки. Если там осуществляется только атомарная операция, это не значит, что объект - не спин-блокировка. Потому что в другом месте, как раз, выполняется именно блокировка в цикле.

    Ну ок, проглядел. Слишком жалко было много времени тратить на вас.

    Спинлоки есть. Это ячейки памяти, которые в данной функции используются как атомики. Да, здесь нет циклов, однако всё равно мы имеем несколько атомарных операций, которые значительно замедляют работу.
    Это во-первых.
    Во-вторых, на выделение shared-объекта мы дёргаем heap, а это тоже нехорошо: мы тратим время на сам вызов + heap сильно фрагментируется.


    Ха-ха, ну ок, оптимизируйте. Я просто привёл пример, как в том числе выхлоп компилятора засирается при простых операциях с shared_ptr. То же самое происходит при использовании абсолютно любого шаблона из STL:
    - объём кода кардинально растёт;
    - скорость выполнения падает;
    - скорость компиляции падает;
    - работа с heap непредсказуема;
    - обработки исключений в STL нет от слова совсем;
    - бинарной совместимости между компиляторами и библиотеками нет by design.

    Нет уж, спасибо, я и так уже немного в эту какашку ступил, нырять в чан с дерьмом как-то неохота. Поэтому я лучше попользую C++ как C с классами.
     
    Последнее редактирование модератором: 16 июл 2017
  16. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    CurryHowardIsomorphism,

    Что выше за дизасм - отрезать руки тому кто этот код писал и тому, кто писал дизасм, обоим.
     
  17. DelAlt

    DelAlt Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    62
    Indy,

    Код (ASM):
    1.  
    2. ;   PureBasic - Inlined asm example file
    3. Procedure some_func (*Pointer)
    4.      !   push    rbx
    5.      !   mov     rbx, QWORD PTR [rdi+8]
    6.      !   mov     rdx, QWORD PTR [rdi]
    7.      !   test    rbx, rbx
    8.      !   je      L9
    9.      !   mov     eax, OFFSET FLAT:__gthrw___pthread_key_create(unsigned int*, void (*)(void*))
    10.      !   test    rax, rax
    11.      !   je      L10
    12.      !   lea     rax, [rbx+8]
    13.      !   lock add        DWORD PTR [rax], 1
    14.      !   mov     DWORD PTR [rdx], 20
    15.      !   lock sub        DWORD PTR [rax], 1
    16.      !   je      L17
    17. L8:
    18.      !   pop     rbx
    19.      !   ret
    20. L10:
    21.      !   add     DWORD PTR [rbx+8], 1
    22.      !   mov     DWORD PTR [rdx], 20
    23.      !   mov     eax, DWORD PTR [rbx+8]
    24.      !   lea     edx, [rax-1]
    25.      !   cmp     eax, 1
    26.      !   mov     DWORD PTR [rbx+8], edx
    27.      !   jne     L8
    28.      !   mov     rax, QWORD PTR [rbx]
    29.      !   mov     rdi, rbx
    30.      !   call    [QWORD PTR [rax+16]]
    31.      !   mov     eax, DWORD PTR [rbx+12]
    32.      !   lea     edx, [rax-1]
    33.      !   mov     DWORD PTR [rbx+12], edx
    34.      !   jmp     L15
    35. L9:
    36.      !   mov     DWORD PTR [rdx], 20
    37.      !   pop     rbx
    38.      !   ret
    39. L17:
    40.      !   mov     rax, QWORD PTR [rbx]
    41.      !   mov     rdi, rbx
    42.      !   call    [QWORD PTR [rax+16]]
    43.      !   mov     eax, -1
    44.      !   lock xadd       DWORD PTR [rbx+12], eax
    45. L15:
    46.      !   cmp     eax, 1
    47.      !   jne     L8
    48.      !   mov     rax, QWORD PTR [rbx]
    49.      !   mov     rdi, rbx
    50.      !   pop     rbx
    51.      !   mov     rax, QWORD PTR [rax+24]
    52.      !   jmp     rax
    53. EndProcedure
    54.  
    Вариант предварительный, в процессе портирования.
     
  18. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    DelAlt,

    Так там вначале басик скрипт транслируется в фасм и затем фасмом собирается в бинарь. Не нужен дизасм :meeting:
     
  19. CurryHowardIsomorphism

    CurryHowardIsomorphism Member

    Публикаций:
    0
    Регистрация:
    13 май 2017
    Сообщения:
    97
    SadKo, ты написал, при попытке изменить shared_ptr постоянно дёргаются спинлоки — оказалось, что это враньё. _M_add_ref_lock[_nothrow], который ты так яро предъявлял сначала (а потом почему-то перестал) при попытке изменить не вызывается. В ассемблерном коде циклов, которые тебе там померещились при взгляде на прыжок назад, тоже не обнаружено.

    Все эти разговорчики про медленные атомики — это твои попытки увильнуть в сторону и замазать лажу. Речь не начиналась с рассуждений о скорости атомиков.
     
  20. Eagle

    Eagle New Member

    Публикаций:
    0
    Регистрация:
    25 июн 2017
    Сообщения:
    6
    ой, прям как дети :

    ...код operator=() ...


    __shared_count&
    operator=(const __shared_count& __r) noexcept
    {
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
    if (__tmp != _M_pi)
    {
    if (__tmp != 0)
    __tmp->_M_add_ref_copy();
    if (_M_pi != 0)
    _M_pi->_M_release();
    _M_pi = __tmp;
    }
    return *this;
    }
    ...

    ... код _M_add_ref_copy() ...


    void
    _M_add_ref_copy()
    { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }

    .
    ..код atomic_add_dispatch() ...


    #ifdef __GTHREADS
    if (__gthread_active_p())
    __atomic_add(__mem, __val);
    else
    __atomic_add_single(__mem, __val);
    #else
    __atomic_add_single(__mem, __val);
    #endif
    ...код __atomic_add() ...
    static inline void
    __atomic_add(volatile _Atomic_word* __mem, int __val)
    { __atomic_fetch_add(__mem, __val, 4); }


    смотрим реализацию макроса__atomic_fetch_add() в gcc-x.x/libatomic/*.h/*.c

    ...
    UTYPE ret;
    UWORD magic;
    pre_seq_barrier (smodel);
    magic = protect_start (mptr);
    ret = *mptr;
    *mptr = OP(ret, opval);
    protect_end (mptr, magic);
    post_seq_barrier (smodel);
    return ret;


    .. далее по тексту ...


    static inline UWORD
    protect_start (void *ptr)
    {
    libat_lock_1 (ptr);
    return 0;
    }

    static inline void
    protect_end (void *ptr, UWORD dummy __attribute__((unused)))
    {
    libat_unlock_1 (ptr);
    }


    ... там же в libatomic/config/* например для posix ...


    void
    libat_lock_1 (void *ptr)
    {
    pthread_mutex_lock (&locks[addr_hash (ptr)].mutex);
    }
    void
    libat_unlock_1 (void *ptr)
    {
    pthread_mutex_unlock (&locks[addr_hash (ptr)].mutex);
    }


    pthread_mutex_*lock() реализуется в частности с помощью lock префикса, открываем manual от интеля:

    https://www.intel.com/content/dam/w...4-ia-32-architectures-optimization-manual.pdf

    стр. 167

    ...
    It is important to avoid operations that work against locality-enhancing techniques. Using the lock prefix heavily can incur large delays when accessing memory, regardless of whether the data is in the cache or in system memory.
    ...

    Edited: строки слиплись ;)