Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2014.05.04;
Скачать: CL | DM;

Вниз

СТРОКИ НЕ ПОТОКОБЕЗОПАСНЫ   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.66 MB
Время: 0.017 c
15-1383253856
Пит
2013-11-01 01:10
2014.05.04
Мышка слишком быстрая


4-1268997623
Alex_C
2010-03-19 14:20
2014.05.04
Требование админ прав на 64-битной XP


15-1383220486
DevilDevil
2013-10-31 15:54
2014.05.04
СТРОКИ НЕ ПОТОКОБЕЗОПАСНЫ


15-1383833853
Ptr_Suspend
2013-11-07 18:17
2014.05.04
Как сделать фунцкию LoWord()?


15-1383683403
Юрий
2013-11-06 00:30
2014.05.04
С днем рождения ! 6 ноября 2013 среда