Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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
2-1374666583
OZ
2013-07-24 15:49
2014.05.04
функция Format


15-1383518806
DevilDevil
2013-11-04 02:46
2014.05.04
threadvar, _GetTls, FS:tlsArray


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


15-1383748436
SergP
2013-11-06 18:33
2014.05.04
Динамический массив записей со строками. подскажите


2-1374567086
Loser
2013-07-23 12:11
2014.05.04
Вызов функции из DLL в методе объекта ( c кодом)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский