LINUX.ORG.RU

Как идиоматичнее написать эту функцию на лиспе

 ,


1

5

Продолжаю щупать скобочки, решил попробовать Common Lisp. Написал простенький tcp сервер, сделал на сокетах (usocket). Выглядит страшненько, но не знаю как написать «правильнее», поэтому решил поинтересоваться у гуру:

(defun create-server (port)
  (let ((socket (usocket:socket-listen "127.0.0.1" port :reuse-address t)))
    (unwind-protect
         (loop
           (let ((connection (usocket:socket-accept socket :element-type 'character)))
             (progn
               (usocket:wait-for-input connection :timeout 10)
               (let ((input-data (read-line (usocket:socket-stream connection))))
                 (when (eq input-data nil) (return))
                 (format t "Server input is: ~a~%"  input-data))
               (format (usocket:socket-stream connection) "Pong~%")
               (force-output (usocket:socket-stream connection))
               (usocket:socket-close connection))))
      (progn
        (format t "Closing socket.~%")
        (usocket:socket-close socket)))))

Первое, что мне кажется не очень правильным это три вложенных let. Вроде поправил на:

(defun create-server (port)
  (let ((socket (usocket:socket-listen "127.0.0.1" port :reuse-address t)))
    (unwind-protect
         (loop
           (let* ((connection (usocket:socket-accept socket :element-type 'character))
                  (stream (usocket:socket-stream connection))
                  (input-data (read-line stream nil)))
             (progn
               (usocket:wait-for-input connection :timeout 10)
               (when (eq input-data :eof) (return))
               (format t "Server input is: ~a~%" input-data)
               (format stream "Pong~%")
               (force-output stream)
               (usocket:socket-close connection))))
      (progn
        (format t "Closing socket.~%")
        (usocket:socket-close socket)))))

Но теперь задержка между отправкой с клиента «Ping» и получением «Pong» стала заметна, возможно проблема в том, что я делаю что-то неправильное с stream и читаю/пишу туда раньше времени. Код клиента

(defun create-client (port)
  (let* ((socket (usocket:socket-connect "127.0.0.1" port)))
    (unwind-protect
         (progn
           (format (usocket:socket-stream socket) "Ping~%") 
           (force-output (usocket:socket-stream socket))
           (usocket:wait-for-input socket :timeout 10)
           (format t "Input is: ~a~%" (read-line (usocket:socket-stream socket))))
      (usocket:socket-close socket))))

Во-вторых, сервер не отрабатывает условие отключения со стороны клиента (пока хочу сделать, чтобы сервер завершал свою работу при отключении клиента). В документации написано:

Reading from a stream which has been closed at the remote end signals an END-OF-FILE condition, meaning that reading from the stream and detecting that condition is the way to do it.

Понимаю только то, что проблема, где-то тут: (when (eq input-data :eof) (return)) – или опять же таки где в моей работе со стримами.

Почему не использую usocket:socket-server? Отвечаю: я так понял, что туда нельзя передать сокет, чтобы ответить что-то клиенту, а же хочу не только читать что мне прислали.

Помогите маленькому лисперу понять что не так. Знаю, что @monk хорошо разбирается в лиспах, из недавнего треда выяснил, что @lovesan в них тоже много понимает и @den73 тоже.

А еще добавлю: loop и sly-interrupt вместе плохо работают? Вижу что в *sly-events for sbcl* отправляется (:emacs-interrupt 2), но REPL все также висит и пишет [sly] REPL is busy

snake266 ★★
() автор топика

Во-первых, используй макросы usocket, они для того и написаны чтобы меньше путаться, во-вторых, используй (use-package) пакеты, которые вряд ли будут привносить конфликты имен, вместо префиксов для символов.

:eof

Откуда ты взял это :EOF? Оно по какой причине должно материализоваться?

:element-type 'character

Он и так character по дефолту. А socket-accept берет :element-type из слушающего сокета по дефолту.

(usocket:wait-for-input connection :timeout 10)

Это это тут после блокирующего read-line? Потом, результат надо обрабатывать, т.к. на линупсах и прочих подобных поделиях с корнями из 60х есть EINTR - см ниже.

let ... progn

В let и так implicit progn

Во-вторых, сервер не отрабатывает условие отключения со стороны клиента (пока хочу сделать, чтобы сервер завершал свою работу при отключении клиента).

Зачем тебе цикл тогда?

loop и sly-interrupt вместе плохо работают

Блокирующие системные вызовы оно не прерывает. И вообще к SLY меньше документации итп, оно чаще глючит чем SLIME, и если ноль в этом вопросе, лучше начать со SLIME.

Вот работающее решение

(in-package #:cl-user)

(defpackage #:echo-sockets
  (:use #:cl #:usocket)
  (:export #:create-server
           #:create-client))

(in-package #:echo-sockets)

(defvar *input-timeout-seconds* 10)

(defun connection-wait-for-input (connection)
  (declare (type stream-usocket connection))
  (loop :for timeout = *input-timeout-seconds*
          :then (multiple-value-bind (stream remaining)
                    (wait-for-input connection :timeout timeout)
                  (unless remaining
                    (error 'timeout-error))
                  (and (not stream) remaining))
        :while timeout))

(defun create-server (port)
  (declare (type (unsigned-byte 16) port))
  (with-socket-listener (listener #(127 0 0 1) port :reuse-address t)
    (handler-case
        (with-server-socket (connection (socket-accept listener))
          (connection-wait-for-input connection)
          (let ((stream (socket-stream connection)))
            (format t "Input from client: ~a~%" (read-line stream))
            (write-line "Pong" stream)
            (force-output stream)))
      (timeout-error ()
        (write-line "Client timed out"))
      (end-of-file ()
        (write-line "No input from client"))
      (stream-error ()
        (write-line "Client disconnected prematurely"))))
  (values))

(defun create-client (port)
  (declare (type (unsigned-byte 16) port))
  (handler-case
      (with-client-socket (connection stream #(127 0 0 1) port)
        (write-line "Ping" stream)
        (force-output stream)
        (connection-wait-for-input connection)
        (format t "Input from server: ~a~%" (read-line stream)))
    (timeout-error ()
      (write-line "Server timed out"))
    (end-of-file ()
      (write-line "No input from server"))
    (connection-refused-error ()
      (write-line "Connection refused"))
    (stream-error ()
      (write-line "Server disconnected prematurely")))
  (values))

lovesan ★★
()
Ответ на: комментарий от lovesan

Во-первых, используй макросы usocket, они для того и написаны чтобы меньше путаться

Хмм, в документации такого не нашел, так понимаю надо смотреть непосредственно исходный код?

Откуда ты взял это :EOF? Оно по какой причине должно материализоваться?

Честно признаться увидел в одной из тем на SO. Сначала использовал обычный nil

Это это тут после блокирующего read-line?

read-line блокирующий? Я вот сегодня с утра пришел к выводу, что socket-accept блокирующий. read-line блокирует выполнение пока в stream что-то не окажется?

Зачем тебе цикл тогда?

Добавил, когда сидел и последовательно запускал клиентов и смотрел, что это работает. Потом захотел добавить какую-то проверку если сокет со стороны клиента закрылся.

Блокирующие системные вызовы оно не прерывает. И вообще к SLY меньше документации итп, оно чаще глючит чем SLIME, и если ноль в этом вопросе, лучше начать со SLIME.

Спасибо, попробую. Использовал SLY потому что его по дефолту предлагает Doom Emacs – вот и подумал, что альтернатива вполне себе готовая.

Вот работающее решение

Спасибо! Буду изучать.

snake266 ★★
() автор топика
Последнее исправление: snake266 (всего исправлений: 2)
Ответ на: комментарий от snake266

Хмм, в документации такого не нашел, так понимаю надо смотреть непосредственно исходный код?

Обычно так и делаю. SLIME подсказывает какие там макросы итд. Они, впрочем, простые как полено, если бы их не было, можно было бы самому написать.

read-line блокирующий? Я вот сегодня с утра пришел к выводу, что socket-accept блокирующий. read-line блокирует выполнение пока в stream что-то не окажется?

socket-accept блокирующий, да. Но вообще usocket - простенькая библиотека, поэтому там многого нет. Для конкретно линукса есть библиотека попродвинутее вроде - iolib.

read-line блокирующий по определению - функция не вернет управление пока не считает строку из потока, или не наткнется на EOF.

http://l1sp.org/cl/read-line

Но вообще, с character потоками напрямую через usocket работать довольно туповато. Т.к. в том же SBCL оно поддерживает только ASCII диапазон. По некоторым причинам. Лучше обернуть поток :element-type (unsigned-byte 8) в flexi-streams, например, или руками разбирать данные, через read-sequence + babel

lovesan ★★
()
Ответ на: комментарий от lovesan

Но вообще usocket - простенькая библиотека, поэтому там многого нет. Для конкретно линукса есть библиотека попродвинутее вроде - iolib.

Спасибо, добавил в закладки, но пока я с прицелом на кроссплатформу этот пример накикул – есть один пет проект, куда как раз нужен tcp сервер, со своими особенностями.

Но вообще, с character потоками напрямую через usocket работать довольно туповато. Т.к. в том же SBCL оно поддерживает только ASCII диапазон. По некоторым причинам. Лучше обернуть поток :element-type (unsigned-byte 8) в flexi-streams, например, или руками разбирать данные, через read-sequence + babel

О, спасибо за совет! Я пока работал с character скорее как для простого примера. Но когда буду расширять учту ваш совет про unsigned-byte

snake266 ★★
() автор топика
Ответ на: комментарий от alysnix

Так понятно, что это можно сделать хоть на питоне, хоть на го. Другое дело, что я просто по фану пробую разное, а тут еще и совпало: необходимость tcp-сервера, мои похождения в лиспе и мега срач на лоре на 2,5к сообщений. Как придет настроение начну и го ковырять, вроде как раз говорят, что его любят админы и devops-ы, я в этом направлении сейчас параллельно развиваюсь, помимо основной деятельности.

snake266 ★★
() автор топика
Ответ на: комментарий от slovazap

В последнем случае ты только тратишь своё время

Ну бывает такое что хочется отвлечься от работы и учебы. Играть в игры еще большая трата времени, книжки читаю по настроению (сейчас вот на Лавкрафта подсел), а бывает хотеться чего-то нестандартного из программирования (хотя тоже перекликается с работой). Тут и приходят всякие «брейнфаки». Почему не посмотреть на привычные вещи под другим углом – со стороны «брейнфака»?

(и чужое, задавая сюда вопросы)

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

snake266 ★★
() автор топика
Ответ на: комментарий от monk

А никак, у гошников всегда так - наколеночное говно недоделанное, которое нихрена не обрабатывает ошибки и написано как попало через жопу. И повсюду panic еще. Как на лабах у студентов.

Я тут еще недавно ржал с реализации read-write lock очередным гошником.

https://eli.thegreenplace.net/2019/implementing-reader-writer-locks/

Вот это вот говно они, то есть, предлагают в качестве production-ready решения, это очень смешное. Потом еще бегают везде орут «пасматрите как на го просто писать, не то что на брейнфаке».

Как выглядит реальный продакшн реди r/w лок?

Вот на лиспе

https://github.com/Lovesan/bike/blob/master/src/rwlock.lisp

Или вот на дотнете

https://github.com/microsoft/referencesource/blob/master/System.Core/System/threading/ReaderWriterLockSlim/ReaderWriterLockSlim.cs

(1700 строк! но гошникам непонятно зачем они там, ессно, т.к. они тупые)

lovesan ★★
()
Ответ на: комментарий от lovesan

Спасибо за пример как «как выстрелить себе в ногу» на Лиспе.

Рекурсивные мьютексы не защищают инварианты, а нафиг они тогда нужны? Если у вас потребность в рекурсивных мьютексах - у вас плохая архитектура и нужно менять ее, а не рекурсию сувать.

Вот неплохое объяснение почему в Go от них отказались.

Obezyan
()
Ответ на: комментарий от Obezyan

Очередные рассуждения человека который вообще нихера(от слова совсем) не понимает в IT, и программировании в частности(тебя), плюс «ненужно» от гошников, которое просто смешно читать, потому что «ненужно» у этих дебилоидов буквально все - от ООП и генериков до нормальной системы работы с зависимостями.

Кстати, в golang примитивы синхронизации всратые в т.ч. потому что там есть горутины, которые вообще примерно никак не сочетаются с ними, а тупо конфликтуют.

lovesan ★★
()
Ответ на: комментарий от Obezyan

Да ты и в PHP вряд ли что-то шаришь.

Почитайте пока обсыхаете: http://www.zaval.org/resources/library/butenhof1.html

Первое что в гугле нашел?

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

Рекурсивные локи используются в рекурсивных функциях, дебик. Щас еще перни, что рекурсия не нужна.

lovesan ★★
()
Ответ на: комментарий от lovesan

Но даже безотносительно рекурсии и реентрабельности - у дебилоидов в голанге нету даже механизма апгрейда лока. Вообще, то есть. Это полный трешак, что ставит ихний rwlock на уровень со студенческими лабами курса эдак второго. Впрочем весь код на го такой.

lovesan ★★
()
Ответ на: комментарий от lovesan

Не поддерживает ни рекурсию, ни апргейд, нихера.

базовый мьютекс не рекурсивный.

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

RecursiveMutex::lock_recursive() {
  if (not this->locked()) this->lock(); ///если не залочен, залочить нерекурсивно
  ++this->lock_counter; ///увеличить счетчик локов
}

RecursiveMutex::unlock_recursive() {
  if (not this->locked_by_me()) panic(); ///нелишняя проверочка, их может быть несколько
  if (--this->lock_counter == 0) this->unlock(); //нерекурсивный анлок
}

итак. базовый мьютекс - нерекурсивный. рекурсивный получается из базового.

применяются они для разных сценариев.


рекурсивный мьютекс:

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

против: даже повторный рекурсивный лок, требует проверки нерекурсивной залоченности, и анлока с проверками, что есть время. если рекурсивные функции мелкие, то можно нехило упасть по производительности. то есть если охраняемый код сравним по сложности с кодом рекурсивных локов/анлоков. это мы еще не рассматривали всякие там кеши, поскольку нужен доступ к обьекту мьютекса.


нерекурсивный мьютекс:

ЗА: есть база для рекурсивного. можно писать самый быстрый код, правильно приготовив последний.


обьявлять базовый нерекурсивный мьюьекс - «студенческим поделием» - это смело. он есть везде, где есть треды. смотри позикс и прочее.


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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

итак. базовый мьютекс - нерекурсивный. рекурсивный получается из базового.

А теперь RWLock сделай такой же, а не мьютекс. Потому что речь не о мьютексе. В глаза не долбись.

lovesan ★★
()
Ответ на: комментарий от lovesan

наследуешься от нерекурсивного rwlock, заводишь два счетчика - r-локов, и w-локов. и делаешь все как, в коде выше. только для двух счетчиков.

кстати ты там код какого-то rw лок на лиспе дал. он вообще устойчив к например разлочке не теми тредами, что лочили, например r канал? то есть r-локнул один один тред, а анлокнул - другой?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от alysnix

кстати ты там код какого-то rw лок на лиспе дал. он вообще устойчив к например разлочке не теми тредами, что лочили, например r канал? то есть r-локнул один один тред, а анлокнул - другой?

Естественно

lovesan ★★
()
Ответ на: комментарий от lovesan

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

(defun rwlock-end-read (rwlock)
  (declare (type rwlock rwlock))
  (with-accessors ((lock %rwlock-cv-lock)
                   (writer-cv %rwlock-writer-cv)
                   (upgrade-cv %rwlock-upgrade-cv)
                   (reader-count %rwlock-reader-count)
                   (waiting-writer-count %rwlock-waiting-writer-count)
                   (waiting-upgrade-count %rwlock-waiting-upgrade-count)
                   (writer %rwlock-writer))
      rwlock
    (let ((self (bt2:current-thread))
          wake-writer wake-upgrading)
      (bt2:with-lock-held (lock)
        (rwlock-modify-count rwlock self :reader-delta -1)
        (when (zerop reader-count)
          ;; prefer waking up upgrading readers
          (cond ((plusp waiting-upgrade-count)
                 (setf wake-upgrading t))
                ((plusp waiting-writer-count)
                 (setf wake-writer t)))))
      (when wake-writer (bt2:condition-notify writer-cv))
      (when wake-upgrading (bt2:condition-notify upgrade-cv))))
  (values))

поскольку я в лиспе совсем никак, то не могу понять где это в данной функции. или это вообще не та функция?

а как тут раскрашивают лисповый код? вон у топикстартера красиво

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 3)
Ответ на: комментарий от unC0Rr

угу. сильно быстро писали. там проверка на залоченность текущим тредом должна быть. как во второй функции

RecursiveMutex::lock_recursive() {
  if (not this->locked_by_me()) this->lock(); ///если не залочен мною, залочить нерекурсивно
  ++this->lock_counter; ///увеличить счетчик локов
}
alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от lovesan
(defun rwlock-modify-count (rwlock thread &key (reader-delta 0)
                                               (writer-delta 0)
                                               (upgrade-delta 0))
  (declare (type rwlock rwlock)
           (type fixnum reader-delta writer-delta upgrade-delta))
  (let ((info (rwlock-thread-info rwlock thread t)))
    (macrolet ((modify (rwlock-accessor info-accessor delta error-name)
                 `(unless (zerop ,delta)
                    (let ((new-global-count (+ (,rwlock-accessor rwlock) ,delta))
                          (new-thread-count (+ (,info-accessor info) ,delta)))
                      (when (minusp new-global-count)
                        (error "Negative ~a count in rwlock ~s"
                               ,error-name rwlock))
                      (when (minusp new-thread-count)
                        (error "Negative thread ~s ~a count in rwlock ~s"
                               thread ,error-name rwlock))
                      (setf (,rwlock-accessor rwlock) new-global-count
                            (,info-accessor info) new-thread-count)))))
      (modify %rwlock-reader-count rwlti-read-count reader-delta "read")
      (modify %rwlock-writer-count rwlti-write-count writer-delta "write")
      (modify %rwlock-upgrading-count rwlti-upgrade-count upgrade-delta "upgrade")
      (when (and (zerop (rwlti-read-count info))
                 (zerop (rwlti-write-count info))
                 (zerop (rwlti-upgrade-count info)))
        (setf (rwlti-thread info) nil))
      info)))

функция увидит что счетчик становится отрицательным

lovesan ★★
()
Ответ на: комментарий от lovesan

Первое что в гугле нашел? Рекурсивные локи используются в рекурсивных функциях, дебик. Щас еще перни, что рекурсия не нужна.

Вот именно поэтому вас ни на один приличный проект не берут, не потому что лисп, а потому что не умеете признавать свою некомпетентность в том или ином вопросе. Попадаете на проекты вы исключительно по недосмотру.

Вы ведь сейчас не со мной, вы сейчас с архитектом из RedHat, автором «Programming with POSIX Threads» спорите.

Смотрите, ладно я - обезъян, ладно, авторы Go могут что-то не понимать, но один из тех кто принимал непосредственное участие в создании этих самых мьютексов в POSIX вряд ли не понимает о чем говорит. В отличии от вас.

Лавсан, Лавсанчик, Лавсанище - хватит крутить жопкой. Вы утверждаете что гошный rwmutex - говно тк не поддерживает рекурсию, я вам отвечаю что рекурсивный мьютекс это грязный хак который применяется когда с архитектурой программы что-то не так. Т.к. цель Go - создание когда в жестких рамках (что помимо прочего дает отличную портируемость на все платформы) то они просто сказали что это говно и объяснили почему.

Но вам так нужно доказать что ваши знания что-то стоят что вы опять идете против здравого смысла вместо того чтобы признать что ошиблись, поблагодарить за новые знания и пойти дальше. Именно такое поведение отличает мужчину от мальчика в разработке :)

Obezyan
()
Ответ на: комментарий от Obezyan

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

Е-мое, в ойтишечке теперь такие критерии? Готов признать свою некомпетентность в любом вопросе за нормальную зарплату.

рекурсивный мьютекс это грязный хак который применяется когда с архитектурой программы что-то не так

А если относиться к этому как к механизму дополнительной страховки? А то эдак и смартпойнтеры - грязный хак и признак рукожопия.

thesis ★★★★★
()
Ответ на: комментарий от lovesan

А теперь RWLock сделай такой же, а не мьютекс. Потому что речь не о мьютексе. В глаза не долбись.

этот же персонаж пару постов выше:

Ты сорцы его видел? https://github.com/golang/go/blob/master/src/sync/rwmutex.go

Видел, а вы вы хоть открывали? там сходу

type RWMutex struct {
	w           Mutex        // held if there are pending writers
	writerSem   uint32       // semaphore for writers to wait for completing readers
	readerSem   uint32       // semaphore for readers to wait for completing writers
	readerCount atomic.Int32 // number of pending readers
	readerWait  atomic.Int32 // number of departing readers
}

и ниже RWLock

// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (rw *RWMutex) Lock() {
   ...

Лавсан, Лавсанчик, Лавсанище.

Obezyan
()
Ответ на: комментарий от thesis

Е-мое, в ойтишечке теперь такие критерии? Готов признать свою некомпетентность в любом вопросе за нормальную зарплату.

В большом проекте ослиная упертость может стоить очень дорого.

А если относиться к этому как к механизму дополнительной страховки? А то эдак и смартпойнтеры - грязный хак и признак рукожопия.

Дело в том что никакой дополнительной страховки это не дает. Рекомендую прочитать то что рекомендовал Лавсану: http://www.zaval.org/resources/library/butenhof1.html

Там и история создания всего этого затронута и главные проблемы. Довольно занимательное чтиво.

Obezyan
()

Извини, я не умею писать веб-сервера. Когда мне нужен сервер, я его где-то беру, хоть на Лиспе, хоть на любом другом языке. Слёту могу вспомнить только hunchentoot. Для просмотра его кода надо настроить EMACS, чтобы был переход к определению, и найти команду, как вернуться из перехода к определению на прежнее место. Тогда будет легче изучить исходники. Может быть, кто-то посоветует более простой сервер, чем hunchentoot.

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

Вложенные let - это судьба лиспера. Можешь попробовать действовать по правилами чистого кода и разбить свою функцию на несколько, тогда вложенность уменьшится (код swank так сделан - там куча функций по 2-3 строки)

den73 ★★★★★
()
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от Obezyan

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

lovesan ★★
()
Ответ на: комментарий от lovesan

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

Неприятно, да? Когда в ваш уютный мирок про 95% идиотов вокруг приходит кто-то кто может показать что вы такая же часть этих 95%, а не оставшихся 5% как вы считали :)

Очередной переход на личности, т.к. снова нечего возразить, ни мне, ни разрабам Go, ни автору этих самых реверсивных мьютексов и rw-локов в POSIX. Бедняга потом много лет терзался что его косяк попал в стандарт потому что вот такие вот не шибко умные, но упрямые товарищи возьмут и поднимут это на флаг, вместо того чтобы зрить в корень.

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

Obezyan
()
Ответ на: комментарий от lovesan

не сравнимая с реальными production-ready локами

это какие вообще? только не надо ограничивать список, rw-локом из дотнета и своим собственным на лиспе.

rw лок со списком ридеров жутко медленный. там приходится все время искать текущий тред в списке ридеров. а если их много-премного?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

это какие вообще? только не надо ограничивать список, rw-локом из дотнета и своим собственным на лиспе.

Можешь еще какую-нибудь жабку посмотреть

rw лок со списком ридеров жутко медленный. там приходится все время искать текущий тред в списке ридеров. а если их много-премного?

Лол, типичное мнение из C++ мирка о производительности.

Когда у тебя прямо много тредов которые долбятся в один лок, да или вообще, много тредов, у тебя там проблемы похлеще чем поиск в связном списке и сравнение с указателем в нем.

На порядке даже нескольких сотен, я так подозреваю, это будет быстрее чем даже атомарная операция или тем более сисколл.

lovesan ★★
()
Ответ на: комментарий от Obezyan

Ты понятия не имеешь о чем пишешь вообще, это объективный факт.

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

lovesan ★★
()