LINUX.ORG.RU

Data race

 ,


0

2

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

#include <mutex>
#include <thread>
#include <chrono>
#include <condition_variable>
#include <queue>
#include <memory>
using namespace std;

struct Mes {
	int data = 0;
	bool processed = false;
};

struct Test {
	mutex mtx;
	condition_variable cv;
	queue<weak_ptr<Mes>> mes_queue;
	int read();
	bool check();
} t;

int Test::read()
{
	auto sh_ptr = make_shared<Mes>();
	unique_lock lck{mtx};
	mes_queue.push(sh_ptr);
	while (! cv.wait_for(lck, 1s, [&sh_ptr](){
				return sh_ptr->processed == true;})  &&  true);
	return sh_ptr->data;
}

bool Test::check()
{
	scoped_lock lck{mtx};

	bool ret = mes_queue.size();
	while (mes_queue.size()) {
		if (shared_ptr<Mes> mes = mes_queue.front().lock()) {
			mes->data = 5;
			mes->processed = true;
		}
		mes_queue.pop();
	}
	cv.notify_all();
	return ret;
}

void read_th() {
	while (true) {
		t.read();
		this_thread::sleep_for(200ms);
	}
}

void check_th() {
	while (true) {
		t.check();
		this_thread::sleep_for(200ms);
	}
}

int main() {
	jthread tr{read_th};
	jthread tc{check_th};
}

$ g++ -pthread -std=c++20 -fsanitize=thread test.cc

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

★★
Ответ на: комментарий от alysnix

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

Читай выше про smt. У него плохо с аргументацией, да. Да и у тебя так же.

И ты задаёшь вопросы дерьма уровня «а у меня там в пхп» - да мне насрать что там у тебя в пхп. Для макаки есть макака-инструментарий - используй его. Только непонятно зачем ты куда-то лезешь и проецируешь макака-проблемы на пацанов, у которых их нет?

Допустим, зачем мне много тредов? Я в принципе не представляю. Расскажи мне.

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

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

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

вы реально считаете, что тредам не нужно ожидание вообще, все решается поллингом?

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

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

вы реально считаете, что тредам не нужно ожидание вообще, все решается поллингом?

Я реально считаю что у Вас каша в голове, и Вы не до конца понимаете что такое thread, вот и всё.

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

Допустим, зачем мне много тредов? Я в принципе не представляю. Расскажи мне.

давай тебе расскажет гугл. а то не поверишь. https://www.google.ru/search?ie=UTF-8&q=why%20do%20we%20need%20threads

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

во блин. нормальная ссыла https://www.ibm.com/docs/en/aix/7.1?topic=programming-benefits-threads

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

Я реально считаю что у Вас каша в голове, и Вы не до конца понимаете что такое thread, вот и всё.

хватит бегать между струйками.

вас же спросили - ни один ваш примитив не умеет переводить тред в ожидание. как вы это собираетесь делать…?

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

вас же спросили - ни один ваш примитив не умеет переводить тред в ожидание. как вы это собираетесь делать…?

Ни-че-го. Именно так. И в контексте моей задачи - мне это не нужно. Повторюсь - дайте мне гарантированный отклик за 1мкс. И ваша жизнь «удалась» после этого. Я не шучу сейчас…

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

Ни-че-го. Именно так. И в контексте моей задачи - мне это не нужно.

ваша «задача» никого не интересует. у всех свои задачи.

вы же делали свое заявление с претензией на всеобщность? если это решает только вашу конкретную задачу… то кому до этого дело вообще?

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

ваша «задача» никого не интересует. у всех свои задачи.

Как там первый Поршик поживает? Маслецо ужо сменили?

вы же делали свое заявление с претензией на всеобщность? если это решает только вашу конкретную задачу… то кому до этого дело вообще?

Нет. Именно вы заявили о 3х «единственно правильных» примитивах. И когда вас начали макАть моськой сами знаете куда - вы тут же слились.

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

Ну наконе-то! Хоть кто то озвучил. Теперь - а как spin lock эффективно сделать без CAS?

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

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

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

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

Очередной бред.

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

Именно вы заявили о 3х «единственно правильных» примитивах.

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

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

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

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

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

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

Очередной бред.

ищите этот кусок в тексте - https://0xax.gitbooks.io/linux-insides/content/SyncPrim/linux-sync-4.html

At the next step we start to spin in the next loop:

while (true) {
    owner = READ_ONCE(lock->owner);

    if (owner && !mutex_spin_on_owner(lock, owner))
        break;

    if (mutex_try_to_acquire(lock)) {
        lock_acquired(&lock->dep_map, ip);

        mutex_set_owner(lock);
        osq_unlock(&lock->osq);
        return true;
    }
}
alysnix ★★★
()
Ответ на: комментарий от alysnix

Ты непонятно кому отвечаешь. И ты так и не ответил. Мне ненужны «зачем вообще треды». Мне нужно про «зачем их много?».

И да, важен контекст. Нужно макаке не значит нужно пацану.

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

что делать то. Как «удалась» жизнь сделать? Подробнее.

Добиться отклика под 1мкс, и самое сложное - убедить меня в том что оно работает.

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

и самое сложное - убедить меня в том что оно работает.

Ищешь пути отступления?

Добиться отклика под 1мкс

Давай, как проверять будем? И отклика чего, поподробнее.

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

Вообще говоря мне казалось glibc’шные mutexes построены напрямую поверх кернеловых Futex. Я что-то упустил?

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

          do
	    {
	      if (cnt++ >= max_cnt)
		{
		  LLL_MUTEX_LOCK (mutex);
		  break;
		}
	      atomic_spin_nop ();
	    }
	  while (LLL_MUTEX_TRYLOCK (mutex) != 0);
alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от anonymous

и самое сложное - убедить меня в том что оно работает.

Ищешь пути отступления?

Не без того, но я думаю - договоримся по любому ;)

Добиться отклика под 1мкс

Давай, как проверять будем? И отклика чего, поподробнее.

От packet in до packet out. Время на дополнительную обработку условно пренебрежимо мало. Не в этом проблема.

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

От packet in до packet out. Время на дополнительную обработку условно пренебрежимо мало. Не в этом проблема.

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

У тебя настолько мусорное api поверх железяки, что сложно сделать 1мкс memcpy, условно(раз у тебя там время обработки мало)? Если твоя железяка в 1мкс не может - это не софтварная проблема.

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

Я не вижу проблем показать 1мкс, если железяка в это может. Мне нужно будет разобраться в твоих железяках, т.к. я этим не занимаюсь, но может поиграться. Я не против. Если ты не уйдёшь в закат, конечно же.

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

И в чём у тебя здесь проблема?

Реально? Мы одни такие тормозы, и все вокруг давно научились за 1мкс всё делать? Уточню - реагировать нужно на сетевые пакеты. Выхлоп - пакет который ушёл.

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

Реально? Мы одни такие тормозы, и все вокруг давно научились за 1мкс всё делать?

Ну ты мне расскажи. Ты ни на один вопрос не можешь ответить.

К тому же кто это все? Есть я, а есть ты(кто-то ещё). Зачем ты пытаешься мазаться?

Уточню - реагировать нужно на сетевые пакеты.

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

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

Во вторых - ведь существующая реализация покрывает все real-life use-cases, no?

Да, но для атомарных операций нужно пользоваться специальными функциями, которыми не все пользуются. Поэтому в С++20 и решили подправить std::atomic, чтобы он мог работать с std::shared_ptr.

Специальные функции: https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic

Пример того что std::shared_ptr не потокобезопасный: https://gcc.godbolt.org/z/djr66Mx8W

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

А это нормально? (немного изменил пример, atomic вместо ш_птр)

#include <iostream>
#include <memory>
#include <thread>
#include <atomic>
using namespace std;

atomic<int> *global_instance = new atomic<int>;
void thread_fcn();

int main(int argc, char** argv) {
  {
    jthread thread1(thread_fcn);
    jthread thread2(thread_fcn);
    jthread thread3(thread_fcn);
    jthread thread4(thread_fcn);
    jthread thread5(thread_fcn);
    jthread thread6(thread_fcn);
    jthread thread7(thread_fcn);
    jthread thread8(thread_fcn);
    jthread thread9(thread_fcn);
    jthread thread10(thread_fcn);
  }

  std::cout << *global_instance << '\n';
}

void thread_fcn() {
  for (int i = 0; i < 10000; i++) {
    *global_instance = ++ *global_instance;
  }
}

$ ./a.out
52719

говорят, что оператор ++ «Atomically increments the current value. The operation is read-modify-write operation». Но нет же?

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

Ой, туплю, переделал криво и удивляюсь. Хотел так написать:

  for (int i = 0; i < 10000; i++) {
    ++ *global_instance;

так норм.

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

Тут shared_ptr не виноват и

В inet полно реализаций классов для многопотока.
Скачайте и разберитесь …

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

Реально? Мы одни такие тормозы, …

@bugfixer, озвучьте как надо, а то тред прям в детектив превратился или что-то типа

В голове у меня бегуди, а на большее ты не рассчитывай ...
anonymous
()
Ответ на: комментарий от anonymous

В inet полно реализаций классов для многопотока. Скачайте и разберитесь …

Триста лет назад сам так сделал.
Скачал, сделал рефакторинг, проверил и отладил, …
И вроде все Ok!

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

Т.е. по-вашему вот это непотокобезопасно?

shared_ptr<int> i = make_shared<int>(5);

int main() {
	auto f = [](){
		cout << *i << endl;
	};
	jthread t1(f);
	jthread t2(f);
	jthread t3(f);
}

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

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

Вообще этот код не смотрел … Не придумывайте

Эшо раз …
Скачайте хороший готовый class, разберитесь и радуйтесь.

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

Эшо раз …
Скачайте хороший готовый class, разберитесь и радуйтесь.

Надеялся в этом треде, что-то новое узнать, а в нем одни

Разборки
anonymous
()
Ответ на: комментарий от Keltir

объясните пожалуйста, спинлок - это бизивейт? как крутить код может быть быстрее чем ожидание (невыполнения кода)?

anonymous
()

Надеюсь тред будет продолжен …

Хорошо бы без разборок
anonymous
()
Ответ на: удаленный комментарий

ты решение-то предложил для задачи, что тебе поставили?

какой задачи, клоун? задача - от приема пакета до отсылки 1 мкс - это не постановка задачи.

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

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

вопрос сформулирован так - пойди туда, не знаю куда и принеси за одну микросекунду.

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

а делать некие исследования, просто ради понтов в треде - я естессно не буду, мне заняться что ли нечем?


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

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

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

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

это уровень регистров, битов, прерываний, так драйверы устройств пишут.

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

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

Я обещался предоставить любое железо по требованию, я не то что я считаю «способно». Но это всё уже монопенисуально - мы приняли решение что и сами разберёмся. Спасибо за внимание.

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

@kvpfs, простите меня снова, пожалуйста, за относительный офтоп. И опять не удержался… С другой стороны - какое-никакое развлечение, правда? :-)

получив аппаратное прерывание от вашего контроллера

Вы отдаёте себе отчёт сколько времени вот это всё займёт?

Уверяю вас, если вы придёте в любую контору которая так или иначе вовлечёна в HFT (типа Цитадели) с рабочим решением которое делает примерно следующее:

  • берёт пакет с NIC (пару сотен байт, не больше)
  • пробрасывает его в userspace
  • там его парсят
  • выгрызают циферки
  • принимают решение «а стоит ли оно того»
  • потенциально отвечают

И вот это всё занимает меньше 1мкс - вас с руками отрывают, платят много-много денюжков сразу (на заряженный Поршик точно хватит, а то и 10), дают хорошую должность / зарплату, и вы после этого как сыр в масле катаетесь… И конкретно в этом мире никто не захочет связываться с ПЛИС по простой причине - оно долго и дорого в разработке (вы хотите иметь возможность менять и деплоить логику на шаге #5 за часы / минуты, тупо потому что этот мир очень изменив). Подумайте об этом, прежде чем в сарказм ударяться. Я может быть вам план на жизнь дарю… Надо быть готовым что на интервью с вами будут разговаривать про MESI, cachelines, store forwarding stalls и тому подобных вещах, а не об 100 тредах на 1ом ядре.

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

@kvpfs, простите меня снова, пожалуйста, за относительный офтоп.

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

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

это кому ответ?

Вам, вам. Перед ТС просто заранее извинился за офтоп.

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

Надо быть готовым что на интервью с вами будут разговаривать про MESI, cachelines, store forwarding stalls и тому подобных вещах, а не об 100 тредах на 1ом ядре.

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

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

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

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

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

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

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

Глубочайшее заблуждение.

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

Глубочайшее заблуждение.

что работа противная, или что много не получают?

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

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

работа реально противная

Мнения разнятся.

а получают примерно по нижней планке для программеров, по крайней мере на российском рынке труда

Что-то мне подсказывает что вы просто не там искали куда продать свои таланты.

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

а не об 100 тредах на 1ом ядре.

вот у меня в бубунте сейчас триста тредов с хвостиком крутятся, а открыт только файрфокс и так, терминалы по мелочи.

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

а тредмакс в кернеле стоит - 60812.

это к сведению о соотношении числа физядер и тредов.

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

вот у меня в бубунте сейчас триста тредов с хвостиком крутятся, а открыт только файрфокс и так, терминалы по мелочи.

это к сведению о соотношении числа физядер и тредов.

Опять «за рыбу деньги». Да кого волнует что происходит на вашем домашнем десктопе? Это ничего общего не имеет с тем с чем приходится иметь дело на условных «боевых серверах». И вообще - какая у вас там частота развертки монитора? Ну пусть даже 240Hz. Это означает что если кто-то от вас потребует реакции в UI быстрее чем за 4 милли то он будет достоен звания почётного идиота. А 4 милли это очень долго, даже на диск можно успеть сходить, на SSD так точно. Ну а уж несколько сотен спящих тредов иметь - так вообще милое дело. Главное чтобы все не возжелали проснуться одновременно…

А, и вот хороший пример - запустите игрушку какую-нибудь (doom, например, из последних), и посмотрите сколько они тредов форкают (операционка вам покажет). Я вас уверяю что сотен там не будет даже близко. А почему? Там тоже предсказуемость важна.

И я, на самом деле, не понимаю что вы так в UI вцепились? Даже IDE свои пишите судя по соседним веткам (если ничего не путаю, но пазл откуда ножки растут начинает складываться). Вот это как раз абсолютно неблагодарное занятие: приходится конкурировать с толпой условных голодных студентов которые готовы на всё, и у которых есть время / желание / энергия осваивать новомодные технологии которые появляются как грибы после дождя с обещаниями сократить время разработки (цена - куча дополнительных уровней абстракции, всё тяжёлое и медленное, но спекам удовлетворяет). Но вы сами выбрали этот путь.

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

Да что ж вы так зациклились на этих 48 ядрах?? Прямо Фрейдом запахло. Это скорее типично для современного серверного железа, и никакой экзотики в этом точно нет. И если вы думаете что я этими ядрами разрасываюсь налево-направо то вы опять глубоко заблуждаетесь. Но пОлить приходится - факт. И ещё - как только у вас появится объективно оправданная производственная необходимость в подобных вычислительных мощностях - я уверен вам их быстро предоставят (ну, в предположении что начальство адекватно, не жлобствует и не самодурит). Задумайтесь - а может вы просто хернёй решили помаяться и вкладывать время в то что никому не нужно? Опять же, ваш выбор - не обвиняйте в этом никого потом.

ПыСы: господи, сколько же я буковок то написал? Как нехарактерно для меня…

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

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.