Форум: "Прочее";
Текущий архив: 2014.05.04;
Скачать: [xml.tar.bz2];
ВнизСТРОКИ НЕ ПОТОКОБЕЗОПАСНЫ Найти похожие ветки
← →
Inovet © (2013-11-01 00:02) [40]> [38] DVM © (31.10.13 23:49)
Ну такое можно и просто в Си++ компиляторах директивами компиляции включить, только поплохеть иногда может.
← →
DevilDevil © (2013-11-01 00:15) [41]> Rouse_ © (31.10.13 23:25) [36]
Розыч, ты говоришь так, будто никогда не ошибаешься
возьмём сегодняшний xchg лол )))
> DVM © (31.10.13 23:26) [37]
> Если две строки указывают на одно и то же место в памяти
> то они равны, если нет, то сравнение выполняется побайтно
ну дак по идее и сейчас никто не мешает сравнивать
более того, при сравнении на равенство строк, эффективно предварительно сравнить длины, а не вызывать каждый раз тяжёлую Compare функцию :)
> NoUser © (01.11.13 00:01) [39]
> В XE4 порадовали AtomicIncrement и прочие AtomicXXX функции.
если не сложно - приведи, чё там в недрах
а то XE4 не ма :)
← →
NoUser © (2013-11-01 00:42) [42]В недрах там просто system.pas, так как попадают в разряд "Delphi Intrinsic Routines" (магия компилятора короче)
Озвучены (в справке) например так:function AtomicExchange(var Target; Value: <Integer or NativeInt or Pointer>): Integer; overload;
;
function AtomicExchange(var Target; Value: <Integer or NativeInt or Pointer>): Int64; overload;
function AtomicExchange(var Target; Value: <Integer or NativeInt or Pointer>): Pointer; overload;
function AtomicExchange(var Target; Value: <Integer or NativeInt or Pointer>): NativeInt; overload
Я как-то пытался заинлайнить самописные, тут вроде спрашивал что-то по асму, и для < XE4 пользую свои Interlocked_xxx (могу выслать)
← →
DevilDevil © (2013-11-01 00:43) [43]> NoUser © (01.11.13 00:42) [42]
ясно
← →
Пит (2013-11-01 01:41) [44]тема интересная.
Конечно, строки не потокобезопасные. Чтобы они стали таковыми - надо при обращении к ним использовать объекты синхронизации, чего по факту по-умолчанию не происходит.
Почему "обычные" строки не потокобезопасные - понятно, зачем расходовать ресурсы на в общем далеко не всем нужную вещь.
Почему нету потокобезопасных строк совместно с потокоопасными - фиг знает, может быть когда и будут.
Но самое любопытное - не припомню, чтобы в реальном коде предпринимались какие либо действия, мотивированные потоко небезопасностью строк. Одна из распространенных ситуаций - когда потоку на инициализацию передают некую строку, ну например адрес хоста, по которому нужно соединиться и забрать какую-то информацию:constructor TMyScannerThread.Create(AHost: string); ...
begin
FHost := AHost;
...
Соответственно, в Execute поток берет из своего private поля значение FHost, присваивает его соответствующему полю компоненту Indy динамически созданному и делает коннект. Оценить насколько здесь важна роль потокобезопасности строк - сложно, на мой взгляд. В более тяжелых примерах - еще сложнее.
Я помню в свое время в таких "подозрительных" моментах делал UniqueString, потом по опыту вижу, что никто и никогда этим "не заморачивается". И сам перестал параноить, по факту всегда все работало хорошо, я не выявлял багов в реальных приложениях, связанных с потокобезопасностью строк, хотя факт потоко небезопасности очевиден.
Засим у меня до сих пор непонятное отношение ко всему этому. Да - строки не потокобезопасные, но почти везде в случае наличия потоков с ними работают так, как будто они потокобезопасные. Есть ли в этом магия или что-то еще - я не знаю, но впечатления и отношение какое-то такое)
← →
DevilDevil © (2013-11-01 01:46) [45]> Пит (01.11.13 01:41) [44]
разобрали вроде уже
пока я остановился в этом вопрос на формулировке [15]
← →
Пит (2013-11-01 02:26) [46]
> разобрали вроде уже
с чем разобрались? )
В [15] написана банальная вещь. Спору нет, так оно и есть, но если условия другие? Распространенное условие я описал в [44] про поток TMyScannerThread
← →
Eraser © (2013-11-01 08:31) [47]
> DevilDevil © (31.10.13 16:44) [15]
я бы в таких спорных местах не использовал бы ARC объекты, а заюзал бы TBytes и самостоятельно разграничил доступ на запись и чтение крит. секциями.
← →
DVM © (2013-11-01 10:14) [48]
> Пит (01.11.13 01:41) [44]
> constructor TMyScannerThread.Create(AHost: string); ...
> begin
> FHost := AHost;
> ...
>
> Соответственно, в Execute поток берет из своего private
> поля значение FHost, присваивает его соответствующему полю
> компоненту Indy динамически созданному и делает коннект.
> Оценить насколько здесь важна роль потокобезопасности строк
> - сложно, на мой взгляд.
Именно в такой записи совсем нет никакой проблемы. Строка будет скопирована, поток будет работать с копией.
← →
DevilDevil © (2013-11-01 10:59) [49]> Пит (01.11.13 02:26) [46]
да, да, как раз хотел написать, то DVM меня опередил
данная ситуация как раз подпадает под формулировку [15]
т.е. переменная FHost находится во владеющем потоке
← →
Cobalt © (2013-11-01 11:33) [50]> Пит (01.11.13 01:41) [44]
Если со строками происходит постоянная безостановочная работа - тогда да, в многопоточном приложении понадобится синхронизация работы с ними.
Но не со всеми подряд, конечно, а "с избранными".
Даже если в цикле запускается пара десятков потоков, каждому из которых передается строка с адресом - все равно сначала увидят что у неё счётчик ссылок >0, сделают себе копию, а потом уже будут фигачить в неё данные.
Тут уж, на мой дилетантский взгляд, есть риск не запортить память, а "потерять её", если два потока одновременно сделают себе копию, и останется оригинал.
← →
jack128_ (2013-11-01 12:00) [51]
> Соответственно, в Execute поток берет из своего private
> поля значение FHost, присваивает его соответствующему полю
> компоненту Indy динамически созданному и делает коннект.
> Оценить насколько здесь важна роль потокобезопасности строк
> - сложно, на мой взгляд.
а что сложного, если не секрет??
> Тут уж, на мой дилетантский взгляд, есть риск не запортить
> память, а "потерять её", если два потока одновременно сделают
> себе копию, и останется оригинал.
нету никакого шанса мемлика для строк. собственно для этого подсчет ссылок и сделан через интерлокед функции.
← →
Владислав © (2013-11-01 12:05) [52]DVM © (01.11.13 10:14) [48]
> Строка будет скопирована, поток будет работать с копией.
С чего бы вдруг?
← →
Пит (2013-11-01 13:29) [53]
> Строка будет скопирована, поток будет работать с копией.
почему строка будет скопирована?
← →
Ega23 © (2013-11-01 13:32) [54]Я бы сказал, неопределённое поведение будет. С одной стороны, при изменении первой, вроде как копия получается. С другой в асме вижу IncRef
← →
Sha © (2013-11-01 14:10) [55]> DevilDevil © (31.10.13 21:42) [25]
> чёт я исходников не вижу...
поверь, они там есть
> но вот здесь вот у тебя большая ошибка в рассуждениях
укажи точное место и какая конкретно ошибка, без общих рассуждений о том, что все знают)
> твой VeryBadCompareInt и есть самый правильный способ сравнения
это где? и какой правильный?
← →
DVM © (2013-11-01 14:17) [56]
> Владислав © (01.11.13 12:05) [52]
> DVM © (01.11.13 10:14) [48]
> > Строка будет скопирована, поток будет работать с копией.
>
>
> С чего бы вдруг?
с того, что по значению передается
← →
DVM © (2013-11-01 14:27) [57]Для разных типов строк кстати по разному это копирование будет проведено. Для коротких строк реально будет скопировано, для AnsiString будет вызвана LStrAddRef и реального копирования не будет, если никто строку изменять не захочет, что будет для других типов строк я не смотрел. Огрести тут проблем шанс минимальный.
← →
DevilDevil © (2013-11-01 14:46) [58]> Sha © (01.11.13 14:10) [55]
> поверь, они там есть
я верю
дай пожалуйста ссылку
OFFTOP
> укажи точное место и какая конкретно ошибка, без общих рассуждений
> о том, что все знают)
> это где? и какой правильный?Получилось быстро, но неверно. Если при вычислении разности произойдет переполнение, то это приведет к ошибочному результату.
Получилось быстро и верно. Ошибочного результата не будет.
← →
Пит (2013-11-01 14:57) [59]
> Для коротких строк реально будет скопировано, для AnsiString
> будет вызвана LStrAddRef и реального копирования не будет
я думал очевидно, что мы ведем речь об Ansi/Wide-string. По-умолчанию, string это AnsiString или WideString, уже очень давно.
И вот так, если сделать: FHost := AHost, а потом это еще присвоить значению .Host компонента Indy - фиг его знает насчет потокобезопасности. Наверное, где-то что-то может и "рвануть", но в реальном коде никогда не видел защиты от этого.
← →
DVM © (2013-11-01 15:02) [60]
> Пит (01.11.13 14:57) [59]
> Ansi/Wide-string
Ты не мешай в одну кучу все строки. Сейчас строки UnicodeString, а не WideString.
WideString вообще особая песня, тоже кстати будет скопировано, если я правильно понял код в system.pas.
← →
Sha © (2013-11-01 15:05) [61]> DevilDevil © (01.11.13 14:46) [58]
> дай пожалуйста ссылку
прямую ссылку дать не могу, там защита от ботов
> Получилось быстро и верно. Ошибочного результата не будет.
Вот тебе пример, что это не так:
Очевидно, что MaxInt>-1.
Но разность MaxInt-(-1)=MaxInt+1=MinInt<0.
Именно поэтому VeryBadCompareInt нигде в Delphi не используется.
← →
DVM © (2013-11-01 15:07) [62]
> И вот так, если сделать: FHost := AHost, а потом это еще
> присвоить значению .Host компонента Indy - фиг его знает
> насчет потокобезопасности. Наверное, где-то что-то может
> и "рвануть"
Вряд ли Indy меняет в процессе работы значение этого поля.
Не может оно рвануть, если со строками обращаться как со строками, а не через указатели, как с массивами и т.д. Если кто-то собирается изменить строку, на которую есть еще ссылки, то этот кто-то сначала получит ее копию, а уж потом будет менять. Компилятор такой код построит сам.
← →
Smile (2013-11-01 15:09) [63]СТРОКИ НЕ ПОТОКОБЕЗОПАСНЫ
Отожми клавишу Caps Lock или убери локоть с клавии Shift
:(
← →
DevilDevil © (2013-11-01 15:24) [64]> Sha © (01.11.13 15:05) [61]
> прямую ссылку дать не могу, там защита от ботов
если не сложно - кинь тогда архивчик
интересно же
> Вот тебе пример, что это не так:
> Очевидно, что MaxInt>-1.
> Но разность MaxInt-(-1)=MaxInt+1=MinInt<0.
> Именно поэтому VeryBadCompareInt нигде в Delphi не используется.
Твоя правда
Публично признаю, что был не прав
оказывается для jl и jg смотрятся не только флаги знака, но и переполнения
p.s. теперь стало понятно, почему в сях принято использовать bool функцию для сортировок
благодарю за то, что ликвидировал ошибку в моих рассуждениях
← →
DevilDevil © (2013-11-01 15:42) [65]> Sha ©
Зацени решение без прыжков, большая часть команд выполнится в конвейере одновременноfunction IntsCompare(const X, Y: integer): integer;
begin
Result := shortint(X >= Y) - shortint(X <= Y);
end;
← →
Sha © (2013-11-01 15:51) [66]> DevilDevil © (01.11.13 15:42) [65]
нечто подобное на BASMе делал,
думаю, Самая быстрая на Земле побыстрее будет
← →
DevilDevil © (2013-11-01 15:55) [67]> думаю, Самая быстрая на Земле побыстрее будет
если ты про это:function ShaCompareInt(Item1, Item2: Pointer): Integer;
var
Second: integer;
begin;
Result:=Integer(Item1^);
Second:=Integer(Item2^);
if Result xor Second>=0
then Result:=Result-Second
else Result:=Result or 1;
end;
end;
То здесь прыжки. А вообще да, нужно организовывать сортировки с минимумом вызываемых функций. PInteger(Item1)^ < PInteger(Item2)^ можно и инлайном делать
← →
Sha © (2013-11-01 15:58) [68]> DevilDevil © (01.11.13 15:55) [67]
> То здесь прыжки.
И че?
← →
DevilDevil © (2013-11-01 16:11) [69]> И че?
эмм
ну не так страшен прыжок, как ошибка его предсказания (длинна конвейера. ~12 тактов)
да и сам прыжок тоже весит
← →
Sha © (2013-11-01 16:14) [70]> DevilDevil © (01.11.13 16:11) [69]
ты не умничай, а просто проверь )
← →
DevilDevil © (2013-11-01 16:19) [71]А вот так кстати вообще ништяк:
function IntsCompare(const X, Y: integer): integer;
begin
Result := shortint(shortint(X >= Y) - shortint(X <= Y));
end;
получается:cmp edx, eax
setle cl
cmp edx, eax
setnl al
sub cl, al
movsx eax, cl
Я насчитал 4 такта на всё
← →
Sha © (2013-11-01 16:27) [72]что-то в этом духе я пробовал, осталось проверить, вдруг звезды сегодня стоят иначе )
← →
DevilDevil © (2013-11-01 16:57) [73]
function DD_CompareInt(Item1, Item2: Pointer): Integer;
var
Second: integer;
begin;
Result := Integer(Item1^);
Second := Integer(Item2^);
Result := shortint(shortint(Result >= Second) - shortint(Result <= Second));
end;
function ShaCompareInt(Item1, Item2: Pointer): Integer;
var
Second: integer;
begin;
Result:=Integer(Item1^);
Second:=Integer(Item2^);
if Result xor Second>=0
then Result:=Result-Second
else Result:=Result or 1;
end;
const
ITERATIONS_COUNT = 10000000;
ARR: array[0..4] of integer = (low(integer), -1, 0, 1, high(integer));
procedure TestDD_();
var
T: dword;
i: integer;
begin
T := GetTickCount;
for i := 1 to ITERATIONS_COUNT do
begin
DD_CompareInt(@ARR[0], @ARR[0]);
DD_CompareInt(@ARR[0], @ARR[1]);
DD_CompareInt(@ARR[0], @ARR[2]);
DD_CompareInt(@ARR[0], @ARR[3]);
DD_CompareInt(@ARR[0], @ARR[4]);
DD_CompareInt(@ARR[1], @ARR[0]);
DD_CompareInt(@ARR[1], @ARR[1]);
DD_CompareInt(@ARR[1], @ARR[2]);
DD_CompareInt(@ARR[1], @ARR[3]);
DD_CompareInt(@ARR[1], @ARR[4]);
DD_CompareInt(@ARR[2], @ARR[0]);
DD_CompareInt(@ARR[2], @ARR[1]);
DD_CompareInt(@ARR[2], @ARR[2]);
DD_CompareInt(@ARR[2], @ARR[3]);
DD_CompareInt(@ARR[2], @ARR[4]);
DD_CompareInt(@ARR[3], @ARR[0]);
DD_CompareInt(@ARR[3], @ARR[1]);
DD_CompareInt(@ARR[3], @ARR[2]);
DD_CompareInt(@ARR[3], @ARR[3]);
DD_CompareInt(@ARR[3], @ARR[4]);
DD_CompareInt(@ARR[4], @ARR[0]);
DD_CompareInt(@ARR[4], @ARR[1]);
DD_CompareInt(@ARR[4], @ARR[2]);
DD_CompareInt(@ARR[4], @ARR[3]);
DD_CompareInt(@ARR[4], @ARR[4]);
end;
T := GetTickCount-T;
Writeln("TestDD_ = ", T, "ms");
end;
procedure TestSha();
var
T: dword;
i: integer;
begin
T := GetTickCount;
for i := 1 to ITERATIONS_COUNT do
begin
ShaCompareInt(@ARR[0], @ARR[0]);
ShaCompareInt(@ARR[0], @ARR[1]);
ShaCompareInt(@ARR[0], @ARR[2]);
ShaCompareInt(@ARR[0], @ARR[3]);
ShaCompareInt(@ARR[0], @ARR[4]);
ShaCompareInt(@ARR[1], @ARR[0]);
ShaCompareInt(@ARR[1], @ARR[1]);
ShaCompareInt(@ARR[1], @ARR[2]);
ShaCompareInt(@ARR[1], @ARR[3]);
ShaCompareInt(@ARR[1], @ARR[4]);
ShaCompareInt(@ARR[2], @ARR[0]);
ShaCompareInt(@ARR[2], @ARR[1]);
ShaCompareInt(@ARR[2], @ARR[2]);
ShaCompareInt(@ARR[2], @ARR[3]);
ShaCompareInt(@ARR[2], @ARR[4]);
ShaCompareInt(@ARR[3], @ARR[0]);
ShaCompareInt(@ARR[3], @ARR[1]);
ShaCompareInt(@ARR[3], @ARR[2]);
ShaCompareInt(@ARR[3], @ARR[3]);
ShaCompareInt(@ARR[3], @ARR[4]);
ShaCompareInt(@ARR[4], @ARR[0]);
ShaCompareInt(@ARR[4], @ARR[1]);
ShaCompareInt(@ARR[4], @ARR[2]);
ShaCompareInt(@ARR[4], @ARR[3]);
ShaCompareInt(@ARR[4], @ARR[4]);
end;
T := GetTickCount-T;
Writeln("TestSha = ", T, "ms");
end;
begin
TestDD_();
TestSha();
Readln;
end.
Результат:
TestDD_ = 420ms-437ms
TestSha = 499ms
Но может на данных приближённых к реальным будет быстрее :)
← →
Хаус (2013-11-01 17:17) [74]
> DevilDevil © (01.11.13 16:57) [73]
Надо еще приоритет потоку поставить высокий,
при таких вычислениях.
← →
Sha © (2013-11-01 17:48) [75]Идея Самой быстрой заключается в том,
что на реальных данных переполнения случаются редко,
и, значит предсказание переходов почти 100%-ное.
Играющая с флагами - то, что было медленно - упрощенная DD_CompareInt
Самая басматая - упрощенная Самая быстрая
У меня на тесте без переполнений результат, естественно другой:
//Самая быстрая
function IntCmp1(px, py: pinteger): integer;
var
t: integer;
begin;
Result:=px^;
t:=py^;
if Result xor t>=0
then Result:=Result-t
else Result:=Result or 1;
end;
//Играющая с флагами
function IntCmp2(px, py: pinteger): integer;
asm
mov eax, dword ptr [eax]
mov edx, dword ptr [edx]
cmp eax, edx
setle cl
setge al
sub al, cl
movsx eax, al
end;
//Самая басматая
function IntCmp3(px, py: pinteger): integer;
asm
mov eax, dword ptr [eax]
mov edx, dword ptr [edx]
sub eax, edx
jo @over
ret
@over:
add eax, edx
or eax, 1
end;
procedure TForm1.Button2Click(Sender: TObject);
var
a: array[0..99] of integer;
t1, t2, t3, i, j: integer;
begin;
RandSeed:=2154376353;
for i:=0 to High(a) do a[i]:=Random(1000000);
t1:=GetTickCount;
for j:=0 to 9999999 do for i:=1 to High(a) do begin;
IntCmp1(@a[i],@a[i-1]);
IntCmp1(@a[i-1],@a[i]);
end;
t1:=GetTickCount-t1;
t2:=GetTickCount;
for j:=0 to 9999999 do for i:=1 to High(a) do begin;
IntCmp2(@a[i],@a[i-1]);
IntCmp2(@a[i-1],@a[i]);
end;
t2:=GetTickCount-t2;
t3:=GetTickCount;
for j:=0 to 9999999 do for i:=1 to High(a) do begin;
IntCmp3(@a[i],@a[i-1]);
IntCmp3(@a[i-1],@a[i]);
end;
t3:=GetTickCount-t3;
Memo1.Lines.Add(IntToStr(t1)); //3104 ms
Memo1.Lines.Add(IntToStr(t2)); //3635 ms
Memo1.Lines.Add(IntToStr(t3)); //3089 ms
end;
← →
Пит (2013-11-01 20:36) [76]
> Ты не мешай в одну кучу все строки. Сейчас строки UnicodeString,
> а не WideString.
да? а чем отличается от WideString?
Я сейчас разговариваю на уровне Delphi 7, там никаких UnicodeString нету..
← →
DevilDevil © (2013-11-01 21:27) [77]> Sha © (01.11.13 17:48) [75]
ясно.
← →
DVM © (2013-11-01 21:44) [78]
> Пит (01.11.13 20:36) [76]
> да? а чем отличается от WideString?
Отличается что? Обычный string, UnicodeString? Управление памятью WideString WideString осуществляется системным менеджером памяти (очень удобно в ряде случаев), обычного string - дельфийским.
← →
DVM © (2013-11-01 22:07) [79]
> Пит (01.11.13 20:36) [76]
Подсчета ссылок в WideString кстати нет вообще, поэтому они и будут копироваться.
← →
Пит (2013-11-01 22:19) [80]
> Отличается что?
WideString от UnicodeString
> Подсчета ссылок в WideString кстати нет вообще
да?! Вот это новость... Я был уверен, что WideString - полная копия AnsiString, только символ двухбайтный.
Страницы: 1 2 3 4 вся ветка
Форум: "Прочее";
Текущий архив: 2014.05.04;
Скачать: [xml.tar.bz2];
Память: 0.64 MB
Время: 0.005 c