Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
1) а)Потому что так говорит Бьерн Страутруп
б)Я отловил прикол, что РакНет не завершает строки нулем, в функции, вызываемой каждым потоком по десять раз за один пакет. При большой сетевой нагрузке, сколько бы ни стоило, будет дорого.
2) Пост про те ситуации, когда в отладчике все хорошо, все нормально. А в рабочем режиме приложение валится.
3) Собственно, про свое исключение и идет речь
#ifdef TRY_DEBUG
#define TRY try
#define CATCH(extra) catch (...) { Logger::throwing extra; throw; }
#else
#define TRY
#define CATCH (extra)
#endif
TRY {
int* x = NULL;
*x =1;
} CATCH(("Unexpected in Foo::Bar"))
queue[i]->push(packet);
i++;
i=i%NumberOfThread;
Обработчик поднял — обработал, поставил пакет в очередь на отправку. Но уже с синхронизацией.
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; //рор проходит
}
Эм… извините, я не понял… Это очередь. Простая, тупая очередь. Один поток умеет добавлять в конец, другой умеет удалять элементы с головы. Какие еще проблемы синхронизации?
void push(T el){
end->el=el; //pop не проходит
end->next=new queue; //pop не проходит
end=end->next; //рор проходит
}
#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 < 10000; ++i) {
push(1);
}
std::cerr << "End";
}
void popper() {
for (;;) {
Value v = pop();
if (v) {
std::cerr << v;
}
}
}
int main() {
end = new queue;
head = end;
std::thread t1(pusher);
std::thread t2(popper);
t1.join();
t2.join();
return 0;
}
$ g++ -std=c++0x -O0 tst.cpp -lpthread -g
$ ./a.out
1111111111111111111111111111111...
$ g++ -std=c++0x -O3 tst.cpp -lpthread -g
$ ./a.out
End^C
#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;
}
Странно. На студии, что с оптимизацией, что без нее, он корректно пишет значения. При этом, я проверяю значения.
Но вообще, я предпочитаю хранить ссылки, ибо ссылка гарантированно пишется за одно обращение. Если я правильно помню курс лекций по ассемблеру. int так же пишется за одно обращение, поэтому это просто общее обращение.
Ничего странного. Просто у вас плохой код, а компилятор плохо оптимизирует. Есть функция popper, который много работает с переменной end. Кешируем её на регистр! Это же будет работать быстрее! Все. Он никогда не увилит изменений в ней. То же самое с функцией pusher, кешируем на регистр и никогда не пишем в память. Это корректное поведение компилятора, ему так делать можно и нужно.
Какго такого ассемблера? При чем тут ассемблер? Вы пишите на C++. Атомарность записи значения гарантируется ТОЛЬКО если вы объявили его atomic. Или вы пишете код, который работает только будучи скомпилированным VS, только на x86, только под windows? Это плохой код. Руководствуйтесь стандартом C++.
Кроме того, я уже говорил, что не гарантируется, что ссылка будет записана ДО того, как будет записан сам объект.
Кроме того, я уже говорил, что не гарантируется, что ссылка будет записана ДО того, как будет записан сам объект.
не пользуйтесь плохим компилятором :-
Знаете, то, что вы сейчас говорите — это дикий ахтунг, который говорит: не пользуйтесь оптимизатором от g++. И вообще не пользуйтесь этим компилятором. Ибо компилятор, из-за которого код в итоге работает не так, как было задумано программистом — это плохой компилятор.
Потому что как было задумано программистом? переменная сохраняется каждый раз в новую область памяти. Где она? Она как была в регистре, так и осталась. Ахтунг.
а)нет нужды кэшировать объект, который используется один раз в обозримом коде.
Потому что я даже не знаю как этот компилятор может использовать кэш, чтобы объект так и не появился в ОЗУ.
Извините, но ваша программа выполняется не на сферическом в вакууме компьютере, а на вполне конкретной архитектуре.
Да, можно писать переносимый код. Но. Он не будет оптимальным.
И моя задача вот конкретно прямо сейчас — выжать из этой архитектуры вообще все что, можно.
та же студия, тот интеловый компилятор смотрят кто ее еще используют. И если ее использует другой поток — она компилится с сохранением в ОЗУ после каждого изменения значения.
Использование try — catch для отладки