Как стать автором
Обновить
8
0

Пользователь

Отправить сообщение
а)Да, про signed/unsigned числа ночью тоже забыл, а сейчас не глянул.
Но назначение кода вы указали правильно — упаковка байт в слово.

б)обычно, смотрю декомпиляторм. IDA или что-нибудь более простое, типа HView, HDasm.
Нет, только про студию и gcc. Есть и специализированные компиляторы.
У неуча шанс облажаться везде стопроцентный.
Вопрос в том, как трудно отловить ошибку и что нужно оптимизировать.
Вы утверждаете, что оптимизировать ничего не надо, ибо наверняка облажаешься.
Это не так. Компилятор делает УНИВЕРСАЛЬНЫЙ код, а не специализированный.
Забыл. В полпервого ночи не мудрено.

мой код на ассме:{
mov ah,b
mov al,c
mov a,ax
}

Код исходного примера, откомпилированного студией, параметры оптимизации: Ot, Ox:
дизассемблер IDA pro 6.1
{
ldarg.0
ldc.i4 0x100
mul
ldarg.1
add
conv.i2

}
Эм… Просто, для примера, задача перекодирования числа в строку.
На ассемблере получается на одну операцию деления меньше, чем делает компилятор.
б) задача, типа (short)A=(char)B<<8+(char)C на ассемблере вообще не требует операций сдвига и сложения, а просто три операции mov

А шанс отстрелить себе ногу есть на чем угодно. К примеру, клиент Wurm-online написан на Яве и тормозит даже на моей машине, показывая картинку ХУЖЕ скайрима, который у меня летает. Это, извините меня, даже не отстреленная нога, это прямой хэдшот.
Кроме того, я уже говорил, что не гарантируется, что ссылка будет записана ДО того, как будет записан сам объект.

не пользуйтесь плохим компилятором :-


Поясняю:
а)нет нужды кэшировать объект, который используется один раз в обозримом коде.

б)Та же переменная end может быть сколько угодно кэширована, но! та же студия, тот интеловый компилятор смотрят кто ее еще используют. И если ее использует другой поток — она компилится с сохранением в ОЗУ после каждого изменения значения.
Ничего странного. Просто у вас плохой код, а компилятор плохо оптимизирует. Есть функция popper, который много работает с переменной end. Кешируем её на регистр! Это же будет работать быстрее! Все. Он никогда не увилит изменений в ней. То же самое с функцией pusher, кешируем на регистр и никогда не пишем в память. Это корректное поведение компилятора, ему так делать можно и нужно.


Знаете, то, что вы сейчас говорите — это дикий ахтунг, который говорит: не пользуйтесь оптимизатором от g++. И вообще не пользуйтесь этим компилятором. Ибо компилятор, из-за которого код в итоге работает не так, как было задумано программистом — это плохой компилятор.

Потому что как было задумано программистом? переменная сохраняется каждый раз в новую область памяти. Где она? Она как была в регистре, так и осталась. Ахтунг. Потому что я даже не знаю как этот компилятор может использовать кэш, чтобы объект так и не появился в ОЗУ.

Какго такого ассемблера? При чем тут ассемблер? Вы пишите на C++. Атомарность записи значения гарантируется ТОЛЬКО если вы объявили его atomic. Или вы пишете код, который работает только будучи скомпилированным VS, только на x86, только под windows? Это плохой код. Руководствуйтесь стандартом C++.


Извините, но ваша программа выполняется не на сферическом в вакууме компьютере, а на вполне конкретной архитектуре. Да, можно писать переносимый код. Но. Он не будет оптимальным. У каждой архитектуры будут свои особенности. И моя задача вот конкретно прямо сейчас — выжать из этой архитектуры вообще все что, можно.

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

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

Код

#include <thread>
#include <iostream>

typedef int Value;

class queue {
public:
	queue() : next(nullptr) {}

	Value el;
	queue* next;
};

queue* head;
queue* end;

Value pop(){
	if (head==end)
		return 0;
	Value el = head->el;
	queue* tmp = head;
	head = head->next;
	delete tmp;
	return el;
}

void push(Value el){
	end->el=el;             //pop не проходит
	end->next = new queue;   //pop не проходит
	end = end->next;        //рор проходит
}

void pusher() {
	for (int i = 0;i < 10000000; ++i) {
		push(i);
	}
	std::cerr << "End";
}

void popper() {
	Value t=0;
	for (;;) {
		Value v = pop();
		if (v) {
			std::cerr << v<<" ";
			if(t+1!=v) {std::cerr << "ERROR!!!"; break;}
			t=v;
		}
	}
}

int main() {
	end = new queue;
	head = end;

	std::thread t1(pusher);
	std::thread t2(popper);
	t1.join();
	t2.join();
	return 0;
}
Постоянно путаю :-) Спасибо :-)
Эм… извините, я не понял… Это очередь. Простая, тупая очередь. Один поток умеет добавлять в конец, другой умеет удалять элементы с головы. Какие еще проблемы синхронизации? Синхронизация нужна тогда и только тогда, когда к одному ресурсу имеет доступ несколько потоков.
Вот псевдо-код

queue* Head;
queue* end;

T pop(){
if(head==end) return NULL;
class T el=head->el;
queue* tmp=head;
head=head->next;
delete tmp;
return el;
}

void push(T el){
end->el=el;             //pop не проходит
end->next=new queue;   //pop не проходит
end=end->next;        //рор проходит
}


Естественно, что в реализации, оно имеет несколько дополнительных проверок, но суть та же.
Да, при записи сообщения к обработчику синхронизации нет. Оно и не нужно — сама структура очереди, механизм добавления в очередь, исключают любую бяку с синхронизацией. Самое страшное, что там случалось — обработчик пропускал итерацию. Но это ничем не грозит.

А вот обратный код требует синхронизации, так как в очередь могут добавлять несколько потоков сразу.
Да, приложение многопоточное. Но валится не приколах с потоками — те максимально разнесены, используя очереди сообщений для межпоточного обмена. Т.е. крутится цикл на прием/отправку.Принял — передал на обработку:
queue[i]->push(packet);
i++;
i=i%NumberOfThread;

Обработчик поднял — обработал, поставил пакет в очередь на отправку. Но уже с синхронизацией.

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

Кроме того, я собираю ВСЕ состояние о системе. Я не стал описывать этого в примере, но в момент обработки try- catch, на следующую итерацию не идет ни один поток. Т.е. я вижу что было с системой на момент падения.

Как я писал выше, приколы возникают в основном со сторонними библиотеками. РакНет, не завершающий строки в пакете нулем(причем, отладочная библиотека завершает нулем пакет, а рабочая — нет), с PostgreSQL тоже что-то было, уже не помню.
1) а)Потому что так говорит Бьерн Страутруп
б)Я отловил прикол, что РакНет не завершает строки нулем, в функции, вызываемой каждым потоком по десять раз за один пакет. При большой сетевой нагрузке, сколько бы ни стоило, будет дорого.
2) Пост про те ситуации, когда в отладчике все хорошо, все нормально. А в рабочем режиме приложение валится.
3) Собственно, про свое исключение и идет речь
4)(посыпаю голову пеплом) в программе так и кидается, а в топике забыл.
12 ...
25

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Дата рождения
Зарегистрирован
Активность