Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2011-06

How to PostMessage to object?

185 messages · 20 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Krzysztof

Hi,

How can I PostMessage from thread to another object? PostMessage/SendMessage need HWND as parameter but this kind of handle is only in visual controls (TWinControl, TForm). I temporary can use TWinControl type instead of TObject but it need parent window to handle messages. Exists any cross platform solution for this? I found only this article for windows (I can't find "DefWindowProc" in lazarus)
http://www.delphidabbler.com/articles?article=1

Regards.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110608/24b236a4/attachment.html>

Reply by email

Michael Schnell
to Krzysztof
Krzysztof wrote
How can I PostMessage from thread to another object?

While "PostMessage()" and "Procedure...Message" is available with Lazarus, you better use the non-Windowish Application.QueueAsyncCall() procedure.

BTW.: with Delphi, you mostly better user TThread.Queue for this purpose.

-Michael

Reply by email

Krzysztof
to Michael Schnell

Hm, I forgot about Application.QueueAsyncCall. And this can be safely call from thread without TThread.Synchronize() ? Because I don't want use Synchronize() in any part of thread code. So this is correct code? :

procedure TMyThread.Execute;
begin
  // <some code here>
  Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some
value')));
  // <some code here>
end;

There is no chance for deadlock with main thread calling this from inside another thread?
But can be problem here if thread try call "Application.QueueAsyncCall" for object which was freed (AV occur). PostMessage just return false if handle doesn't exists.

2011/6/8 Michael Schnell

Show quoted text 18 lines
On 06/08/2011 04:57 PM, Krzysztof wrote: > How can I PostMessage from thread to another object? > While "PostMessage()" and "Procedure...Message" is available with Lazarus, you better use the non-Windowish Application.QueueAsyncCall() procedure. BTW.: with Delphi, you mostly better user TThread.Queue for this purpose. -Michael -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110608/da0c2a64/attachment.html>

Reply by email

Henry Vermaak
to Krzysztof
Krzysztof wrote 14 lines
Hm, I forgot about Application.QueueAsyncCall. And this can be safely call from thread without TThread.Synchronize() ? Because I don't want use Synchronize() in any part of thread code. So this is correct code? : procedure TMyThread.Execute; begin // <some code here> Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some value'))); // <some code here> end; There is no chance for deadlock with main thread calling this from inside another thread?

You have to protect it with a critical section (if you have more than one thread calling QueueAsyncCall).

Henry

Reply by email

Krzysztof
to Henry Vermaak

Ok, this can be done with critical section but what with AV scenario? Example:
1. Thread add queue calling Application.QueueAsyncCall(MyObj.EventMethod, 0);
2. MyObj is destroyed by main thread
3. Main thread process messages and try call queue added by thread but reference to MyObj.EventMethod was destroyed by previous message loop. This cause Access Violation.

I could remove this queue in MyObj destructor but TApplication.FAsyncCall is in private section :/

2011/6/8 Henry Vermaak

Show quoted text 31 lines
On 08/06/11 16:28, Krzysztof wrote: > Hm, I forgot about Application.QueueAsyncCall. And this can be safely > call from thread without TThread.Synchronize() ? Because I don't want > use Synchronize() in any part of thread code. So this is correct code? : > > procedure TMyThread.Execute; > begin > // <some code here> > Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some > value'))); > // <some code here> > end; > > There is no chance for deadlock with main thread calling this from > inside another thread? > You have to protect it with a critical section (if you have more than one thread calling QueueAsyncCall). Henry -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110608/2d4254bd/attachment.html>

Reply by email

Krzysztof
to Krzysztof

Ok, I did not notice that exists method TApplication.RemoveAsyncCalls(const AnObject: TObject). Anyway it's strange that AnObject param is compared to Data param from QueueAsyncCall, not to AMethod, but this is not a problem.

2011/6/8 Krzysztof

Show quoted text 46 lines
Ok, this can be done with critical section but what with AV scenario? Example: 1. Thread add queue calling Application.QueueAsyncCall(MyObj.EventMethod, 0); 2. MyObj is destroyed by main thread 3. Main thread process messages and try call queue added by thread but reference to MyObj.EventMethod was destroyed by previous message loop. This cause Access Violation. I could remove this queue in MyObj destructor but TApplication.FAsyncCall is in private section :/ 2011/6/8 Henry Vermaak > On 08/06/11 16:28, Krzysztof wrote: > >> Hm, I forgot about Application.QueueAsyncCall. And this can be safely >> call from thread without TThread.Synchronize() ? Because I don't want >> use Synchronize() in any part of thread code. So this is correct code? : >> >> procedure TMyThread.Execute; >> begin >> // <some code here> >> Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some >> value'))); >> // <some code here> >> end; >> >> There is no chance for deadlock with main thread calling this from >> inside another thread? >> > > You have to protect it with a critical section (if you have more than one > thread calling QueueAsyncCall). > > Henry > > > -- > _______________________________________________ > Lazarus mailing list > > http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus > >

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110608/5492d740/attachment.html>

Reply by email

Michael Schnell
to Krzysztof: Hm, I forgot about Application.QueueAsyncCall. And this can be safely call from thread…
Krzysztof wrote
Hm, I forgot about Application.QueueAsyncCall. And this can be safely call from thread without TThread.Synchronize() ?

This is exactly what Application.QueueAsyncCall() (and what the Delphi-Worlkalike TThread.Queue() ) does-

Show quoted text 10 lines
Because I don't want use Synchronize() in any part of thread code. So this is correct code? : procedure TMyThread.Execute; begin // <some code here> Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some value'))); // <some code here> end;
here is the code I tested (the thread class offers a proptery
"OnACall_Parameters" as a hook for attaching a Main-Thread handling
procedure):
------------------------------------------------------------------------
Type
   TAsyncData = record
     S: String;
     D: Integer;
   end;
   TPAsyncData = ^TAsyncData;
   TAsyncCall_Parameters = procedure(S: String; D: Integer) of object;
   public
      OnACall_Parameters: TAsyncCall_Parameters;
var
    PAsyncData: TPAsyncData;
begin
   new(PAsyncData);
   PAsyncData^.d:=Global_I;
   PAsyncData^.S:= 'T E S T';
   Application.QueueAsyncCall(@DACall_Parameters, PtrInt(PAsyncData));
end;
procedure TWorkerThread.DACall_Parameters(Data: PtrInt);
var
   PAsyncData: TPAsyncData;
begin
   PAsyncData:=TPAsyncData(Data);
   if assigned(OnACall_Parameters) then
OnACall_Parameters(PAsyncData^.S, PAsyncData^.D);
   Dispose(PAsyncData);
end;
------------------------------------------------------------------------
-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/ece77b5f/attachment.html>

Reply by email

Michael Schnell
to Henry Vermaak: You have to protect it with a critical section (if you have more than one thread calling…
Henry Vermaak wrote 6 lines
> There is no chance for deadlock with main thread calling this from > inside another thread? You have to protect it with a critical section (if you have more than one thread calling QueueAsyncCall).

A critical section likely will kill the thread latency, so this should be avoided

You can fire the same main thread event from many threads. the LCL will queue them and the main thread will handle them one after the other.

If designed properly, a deadlock can't happen. You need to take care that the data is allocated before sending it to the main thread and the main thread deallocates it (see example code).

-Michael

Reply by email

Michael Schnell
to Krzysztof: Ok, this can be done with critical section but what with AV scenario? Example: 1. Thread…
Krzysztof wrote
1. Thread add queue calling Application.QueueAsyncCall(MyObj.EventMethod, 0);

Why does it not create a data storage and provides the pointer ?

2. MyObj is destroyed by main thread

How does the Main thread know about it ?

3. Main thread process messages and try call queue added by thread but reference to MyObj.EventMethod was destroyed by previous message loop.

can't happen if the pointer is transferred with the call request.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/f8fbdef0/attachment.html>

Reply by email

Henry Vermaak
to Michael Schnell: A critical section likely will kill the thread latency, so this should be avoided You can…
Michael Schnell wrote 10 lines
On 06/08/2011 05:39 PM, Henry Vermaak wrote: >> There is no chance for deadlock with main thread calling this from >> inside another thread? > > > You have to protect it with a critical section (if you have more than > one thread calling QueueAsyncCall). A critical section likely will kill the thread latency, so this should be avoided

You will corrupt the linked list that QueueAsyncCall uses when you call it from multiple threads, so you _must_ protect it.

You can fire the same main thread event from many threads. the LCL will queue them and the main thread will handle them one after the other.

It doesn't matter if it's the same event or not, all events are stored in a list by QueueAsyncCall. I don't know why they didn't use a thread-safe queue for this.

Henry

Reply by email

Mattias Gaertner
to Michael Schnell: A critical section likely will kill the thread latency, so this should be avoided You can…

?
?

Michael Schnell hat am 9. Juni 2011 um 10:50 geschrieben:

Show quoted text 10 lines
On 06/08/2011 05:39 PM, Henry Vermaak wrote: >> There is no chance for deadlock with main thread calling this from >> inside another thread? > > > You have to protect it with a critical section (if you have more than > one thread calling QueueAsyncCall). A critical section likely will kill the thread latency, so this should be avoided?

How many calls per second do you want to execute via the main thread?

QueueAsyncCall is *not* thread safe.? If QueueAsyncCall should be made thread safe, then TApplication must be extended to use a critical section for it (or some lock-free queue, but since we are talking about the GUI thread, latency is already so bad, that this makes no difference).
?
Afaik all PostMessages implementations use a critical section. So you don't need to do that yourself.
?
?

[...]

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/eac40b0c/attachment.html>

Reply by email

Michael Schnell
to Henry Vermaak: You will corrupt the linked list that QueueAsyncCall uses when you call it from multiple…
Henry Vermaak wrote
You will corrupt the linked list that QueueAsyncCall() uses when you call it from multiple threads, so you _must_ protect it.

As QueueAsyncCall is specified exactly for this use, it needs to take care of this issue internally. Otherwise it obviously is buggy. I trust that the LCL developers did a decent job.

(The list access needs to be protected even with a single worker thread, as the main thread removes elements in a concurrent access anyway.)

-Michael

Reply by email

Michael Schnell
to Mattias Gaertner: ? ? Michael Schnell hat am 9. Juni 2011 um 10:50 geschrieben: How many calls per second…
Mattias Gaertner wrote
QueueAsyncCall is *not* thread safe.

If this is ture, I would call it a bug, as QueueAsyncCall obviously is designed to be used by threads.

but since we are talking about the GUI thread, latency is already so bad, that this makes no difference).

We are not. The purpose of QueueAsyncCall is to be used in a worker Thread. The delay introduced by the GUI thread that in some remote future is supposed to execute the queued task (e.g. display a progress bar showing how far the worker thread has gotten with its work) is not relevant.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell: As QueueAsyncCall is specified exactly for this use, it needs to take care of this issue…

?
?

Michael Schnell hat am 9. Juni 2011 um 11:46 geschrieben:

Show quoted text 6 lines
On 06/09/2011 10:58 AM, Henry Vermaak wrote: > You will corrupt the linked list that QueueAsyncCall() uses when you > call it from multiple threads, so you _must_ protect it. As QueueAsyncCall is specified exactly for this use, it needs to take care of this issue internally. Otherwise it obviously is buggy. I trust that the LCL developers did a decent job.?

The only "specification" I found for TApplication.QueueAsyncCall is the fpdoc entry:
Insert a given asynchronous call into the queue
?
Why do you think it is thread safe?
?
?
?

(The list access needs to be protected even with a single worker thread, as the main thread removes elements in a concurrent access anyway.)

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/875872a3/attachment.html>

Reply by email

Michael Schnell
to Mattias Gaertner
Mattias Gaertner wrote
Why do you think it is thread safe?

I just trusted that it would be properly designed.

Looking at the code I found that it in fact seems to be buggy.

The linked list is modified both by the (even single) Worker Thread when inserting an element as by the main ("GUI") thread when removing one without protection by a semaphore.

(Without decent analysis) I don't believe that there is no chance of hazard.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/f5c1e228/attachment.html>

Reply by email

Henry Vermaak
to Henry Vermaak: You have to protect it with a critical section (if you have more than one thread calling…
Henry Vermaak wrote 18 lines
On 08/06/11 16:28, Krzysztof wrote: > Hm, I forgot about Application.QueueAsyncCall. And this can be safely > call from thread without TThread.Synchronize() ? Because I don't want > use Synchronize() in any part of thread code. So this is correct code? : > > procedure TMyThread.Execute; > begin > // <some code here> > Application.QueueAsyncCall(@SomeObj.TestMethod, PtrInt(NewStr('Some > value'))); > // <some code here> > end; > > There is no chance for deadlock with main thread calling this from > inside another thread? You have to protect it with a critical section (if you have more than one thread calling QueueAsyncCall).

This will not even solve the problem, since the ProcessAsyncCallQueue and RemoveAsyncCalls also need to be protected. Just use PostMessage for thread communication.

Reply by email

Henry Vermaak
to Mattias Gaertner: ? ? Michael Schnell hat am 9. Juni 2011 um 11:46 geschrieben: The only "specification" I…
Mattias Gaertner wrote 18 lines
Michael Schnell hat am 9. Juni 2011 um 11:46 geschrieben: > On 06/09/2011 10:58 AM, Henry Vermaak wrote: > > You will corrupt the linked list that QueueAsyncCall() uses when you > > call it from multiple threads, so you _must_ protect it. > As QueueAsyncCall is specified exactly for this use, it needs to take > care of this issue internally. Otherwise it obviously is buggy. I trust > that the LCL developers did a decent job. The only "specification" I found for TApplication.QueueAsyncCall is the fpdoc entry: Insert a given asynchronous call into the queue Why do you think it is thread safe?

Do you propose that QueueAsyncCall throws an exception if it's used from outside the main thread? Otherwise adding a critical section to all the async queue methods is in order.

Henry

Reply by email

Michael Schnell
to Henry Vermaak
Henry Vermaak wrote
Do you propose that QueueAsyncCall throws an exception if it's used from outside the main thread?

The purpose of QueueAsyncCall() is to use it in worker threads to notify the main thread of something that happens in the thread (without the worker thread needing to wait that the main thread was able to handle the event). But it's not forbidden to call QueueAsyncCall() in the main thread.

Otherwise adding a critical section to all the async queue methods is in order.

IMOH protecting a call to QueueAsyncCall() (in user code or <IMHO better> in the LCL itself) by a semaphore should not harm anyway in most cases, as there would be no waiting on anything else in that critical section. If you assign different priorities to the threads there of course is the usual problem of priority inversion.

-Michael

Reply by email

Henry Vermaak
to Michael Schnell
Michael Schnell wrote 6 lines
On 06/09/2011 12:12 PM, Henry Vermaak wrote: > > Do you propose that QueueAsyncCall throws an exception if it's used > from outside the main thread? The purpose of QueueAsyncCall() is to use it in worker threads to notify the main thread of something that happens in the thread (without the

Where do you find this "purpose". As Mattias said, the spec says nothing of the sort.

Show quoted text 8 lines
> Otherwise adding a critical section to all the async queue methods is > in order. > IMOH protecting a call to QueueAsyncCall() (in user code or <IMHO better> in the LCL itself) by a semaphore should not harm anyway in most cases, as there would be no waiting on anything else in that critical section. If you assign different priorities to the threads there of course is the usual problem of priority inversion.

Protecting it in user code won't work, since the application can still remove calls while you try and add them. It needs to be protected inside the lcl or fail.

Henry

Reply by email

Michael Schnell
to Henry Vermaak: This will not even solve the problem, since the ProcessAsyncCallQueue and…
Henry Vermaak wrote
This will not even solve the problem, since the ProcessAsyncCallQueue and RemoveAsyncCalls also need to be protected.

This is what I seem to have found, too.
But it can't be done in user code which never calls RemoveAsyncCalls(). If it is really necessary (analyzing the code on that behalf does not seem trivial) it needs to be done within the LCL.

Just use PostMessage for thread communication.

IMHO instead of using the old Windowish stuff, better the problems in the LCL should be resolved.

-Michael

Reply by email

Michael Schnell
to Henry Vermaak: Where do you find this "purpose". As Mattias said, the spec says nothing of the sort.…
Henry Vermaak wrote
Where do you find this "purpose". As Mattias said, the spec says nothing of the sort.

I don't see any other purpose.;-)

Protecting it in user code won't work, since the application can still remove calls while you try and add them. It needs to be protected inside the lcl or fail.

Obviously, here we agree :-) .
Should a issue report be filed ?

-Michael

Reply by email

Mattias Gaertner
to Henry Vermaak: Do you propose that QueueAsyncCall throws an exception if it's used from outside the main…

?
?

Henry Vermaak hat am 9. Juni 2011 um 12:12
geschrieben:

Show quoted text 23 lines
On 09/06/11 11:01, Mattias Gaertner wrote: > > > Michael Schnell hat am 9. Juni 2011 um 11:46 > geschrieben: > >? > On 06/09/2011 10:58 AM, Henry Vermaak wrote: >? > > You will corrupt the linked list that QueueAsyncCall() uses when you >? > > call it from multiple threads, so you _must_ protect it. >? > As QueueAsyncCall is specified exactly for this use, it needs to take >? > care of this issue internally. Otherwise it obviously is buggy. I trust >? > that the LCL developers did a decent job. > > The only "specification" I found for TApplication.QueueAsyncCall is the > fpdoc entry: > > Insert a given asynchronous call into the queue > > Why do you think it is thread safe? Do you propose that QueueAsyncCall throws an exception if it's used from outside the main thread?? Otherwise adding a critical section to all the async queue methods is in order.

I made it thread safe. Please test.

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/709df93e/attachment.html>

Reply by email

Mattias Gaertner
to Michael Schnell: I don't see any other purpose.;-) Obviously, here we agree :-) . Should a issue report be…

?
?

Michael Schnell hat am 9. Juni 2011 um 12:39 geschrieben:

On 06/09/2011 12:30 PM, Henry Vermaak wrote: > Where do you find this "purpose".? As Mattias said, the spec says > nothing of the sort. I don't see any other purpose.;-)?

Well, that is an "argument from ignorance".
?
The purpose is to execute a method outside the event where it was initiated. For example to free a TEdit inside its OnKeyDown event or to switch the focus in an OnEnter event.
?

Mattias

Argument from ignorance
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/707de3d1/attachment.html>

Reply by email

Graeme Geldenhuys
to Mattias Gaertner: ? ? Michael Schnell hat am 9. Juni 2011 um 12:39 geschrieben: Well, that is an "argument…
Mattias Gaertner wrote
Well, that is an "argument from ignorance".

Then the documentation was written by the arrogant - expecting everybody else to be mind readers.

The purpose is to execute a method outside the event where it was initiated. For example to free a TEdit inside its OnKeyDown event or to switch the focus in an OnEnter event.

While you are at it, would you mind updating the documentation for QueueAsyncCall() - thus avoiding any future confusion.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Henry Vermaak
to Mattias Gaertner: ? ? Henry Vermaak hat am 9. Juni 2011 um 12:12 geschrieben: I made it thread safe.…
Mattias Gaertner wrote 32 lines
Henry Vermaak hat am 9. Juni 2011 um 12:12 geschrieben: > On 09/06/11 11:01, Mattias Gaertner wrote: > > > > > > Michael Schnell hat am 9. Juni 2011 um 11:46 > > geschrieben: > > > > > On 06/09/2011 10:58 AM, Henry Vermaak wrote: > > > > You will corrupt the linked list that QueueAsyncCall() uses when you > > > > call it from multiple threads, so you _must_ protect it. > > > As QueueAsyncCall is specified exactly for this use, it needs to take > > > care of this issue internally. Otherwise it obviously is buggy. I trust > > > that the LCL developers did a decent job. > > > > The only "specification" I found for TApplication.QueueAsyncCall is the > > fpdoc entry: > > > > Insert a given asynchronous call into the queue > > > > Why do you think it is thread safe? > > Do you propose that QueueAsyncCall throws an exception if it's used from > outside the main thread? Otherwise adding a critical section to all the > async queue methods is in order. I made it thread safe. Please test.

In TApplication.Destroy there is another call to ProcessAsyncCallQueue further down (line 170). System.DoneCriticalSection(FAsyncCall.CritSec) needs to be moved after it.

Henry

Reply by email

Mattias Gaertner
to Graeme Geldenhuys: Then the documentation was written by the arrogant - expecting everybody else to be mind…

?
?

Graeme Geldenhuys hat am 9. Juni 2011 um 13:22
geschrieben:

Show quoted text 6 lines
On 09/06/2011 13:17, Mattias Gaertner wrote: > > Well, that is an "argument from ignorance". Then the documentation was written by the arrogant - expecting everybody else to be mind readers.?

I think you overstate it. The LCL is not thread safe. It's said on the multi threading tutorial and it is the standard example for TThread.Synchronize.? Only if the documentation explicitly says a method is thread safe it is. Maybe this needs to be made more clear. Any ideas, where? There are a few low level functions like FileExistsUTF8 which are thread safe and needs to be documented that they are.?
?
?

Show quoted text 8 lines
> The purpose is to execute a method outside the event where it was > initiated. For example to free a TEdit inside its OnKeyDown event or to > switch the focus in an OnEnter event. While you are at it, would you mind updating the documentation for QueueAsyncCall() - thus avoiding any future confusion.

Ah, I forgot to commit the docs directory.

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/c457d590/attachment-0001.html>

Reply by email

Mattias Gaertner
to Henry Vermaak: In TApplication.Destroy there is another call to ProcessAsyncCallQueue further down (line…

?
?

Henry Vermaak hat am 9. Juni 2011 um 13:28
geschrieben:

[...]> In TApplication.Destroy there is another call to ProcessAsyncCallQueue further down (line 170).? System.DoneCriticalSection(FAsyncCall.CritSec) needs to be moved after it.

Done.

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/c8e42594/attachment.html>

Reply by email

Michael Schnell
to Mattias Gaertner: ? ? Henry Vermaak hat am 9. Juni 2011 um 12:12 geschrieben: I made it thread safe.…
Mattias Gaertner wrote
I made it thread safe. Please test.

Thanks Mattias, you made my day !

Reading the other messages here, I actually considered unsubscribing from the list and forgetting about Lazarus altogether.

(A decent library needs to be usable ion a threaded project, even of of course not all functions can be genuinely thread safe.)

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/29c6bc31/attachment.html>

Reply by email

Henry Vermaak
to Michael Schnell: Thanks Mattias, you made my day ! Reading the other messages here, I actually considered…
Michael Schnell wrote 9 lines
On 06/09/2011 01:00 PM, Mattias Gaertner wrote: > > I made it thread safe. Please test. > > Thanks Mattias, you made my day ! Reading the other messages here, I actually considered unsubscribing from the list and forgetting about Lazarus altogether.

What pathetic attitude. You can fix these things yourself, but never do. It's always just talk with you, isn't it?

Reply by email

Michael Schnell
to Mattias Gaertner: ? ? Henry Vermaak hat am 9. Juni 2011 um 12:12 geschrieben: I made it thread safe.…
Mattias Gaertner wrote
I made it thread safe. Please test.

I verified that it works with my thread testing project (but I did not notice a problem before).

Some thoughts:

Did you verify that in a single worker thread situation the protection is necessary ? The worker thread only modifies one end of the queue, the main thread only modifies the other end. So hazards are only possible when the queue is nearly empty. No inc or dec seems to be done, so there are chances that it's thread safe by default.

I can't understand, why "RemoveAsyncCalls" seems to remove two entries from the queue. Do you know what is happening there ?

Thanks,
-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/1df14e31/attachment.html>

Reply by email

Michael Schnell
to Henry Vermaak: What pathetic attitude. You can fix these things yourself, but never do. It's always…
Henry Vermaak wrote
What pathetic attitude. You can fix these things yourself, but never do.

I don't want to destroy something that somebody more knowledgeable created.

It's always just talk with you, isn't it?

Right now you are correct. (I do hope that my contributions provide some help for improving the already great tool.)

As you might know I did some active work on a Widget Type some years ago, but found that the results are not according to a standard that I feel valid for publishing.

At the moment, for me the Pascal projects are very low priority, so I can't dedicate much more time than reading the list, providing some thoughts and do some testing. But this might change greatly at some point in time that is not due to my decision.

-Michael

Reply by email

Felipe Monteiro de Carvalho
to Michael Schnell
Michael Schnell wrote
I don't want to destroy something that somebody more knowledgeable created.

This risk does not exist, patches are discussed and reviewed before being applyed.

Felipe Monteiro de Carvalho

Reply by email

Flávio Etrusco
to Henry Vermaak: What pathetic attitude. You can fix these things yourself, but never do. It's always…
Henry Vermaak wrote 16 lines
On 09/06/11 13:04, Michael Schnell wrote: > > ?On 06/09/2011 01:00 PM, Mattias Gaertner wrote: >> >> I made it thread safe. Please test. >> >> > Thanks Mattias, you made my day ! > > Reading the other messages here, I actually considered unsubscribing > from the list and forgetting about Lazarus altogether. What pathetic attitude. ?You can fix these things yourself, but never do. ?It's always just talk with you, isn't it? --

Nobody were asking for patches, just discussing behaviour. And I completely agree with Michael in that QueueAsyncCall ought to be thread-safe (thanks from me too, Mattias!).

-Fl?vio

Reply by email

Krzysztof
to Flávio Etrusco

Huh, 35 new messages in my topic :) . After reading all, maybe I summarize why I need post message to non-windowed object/component and why I can't use PostMessage and for what I need this (on a real example).

So, I wrote TMyHTTPClient which is some kind of layer for synapse http client but it do all jobs in thread. Simply structure:

type
  TMyHTTPClient = class;
  TSynThread = class(TThread)
  private
    FMyHClient: TMyHTTPClient;
    FSynHTTP: THTTPSend;
  end;
  TMyHTTPClient = class
  private
    FSynThread: TSynThread;
  end;

Now, TSynThread communicate with TMyHTTPClient sending progress and response data from server. I used TThread.Synchronize() for this but I often had deadlocks because TMyHTTPClient cares about terminate and free thread (it waiting in destructor until thread terminate). I could not find way to omit deadlocks in case when thread blocking in synchronize() to send progress data and TMyHTTPClient waiting for this thread termination (ProcessMessages and CheckForSynchronize doesn't solve this on linux). So I tried solve this using PostMessage instead of Synchronize but PostMessage need window handle. In simple project, main form should be solution here (as mediator between TMyHTTPClient
and TSynThread) but my project is quite big and I use this http client in many places, in many modules, in many cases (most in non-visual) and in many instances. So I need something simpler. Now you reminded me about Application.QueueAsyncCall and this is point where we are :) . I think that critical section latency in thread is not problem in this case. I try update lazarus source and test your "thread safe" fix for QueueAsyncCall. Maybe my case could be resolved in many different ways, but good communication mechanism between threads, certainly will be useful in other cases :)
Sorry for my bad english, I tried describe it in details.

Regards.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110609/1f0b6c9b/attachment.html>

Reply by email

Hans-Peter Diettrich
to Mattias Gaertner: ? ? Graeme Geldenhuys hat am 9. Juni 2011 um 13:22 geschrieben: I think you overstate…
Only if the documentation explicitly says a method is thread safe it is. Maybe this needs to be made more clear. Any ideas, where?

What is "thread safe"?

There are a few low level functions like FileExistsUTF8 which are thread safe and needs to be documented that they are.

In how far is just FileExistsUTF8 "thread safe"? Even if the file existed at function return, it can have been killed by somebody else immediately after, even from outside the application.

Similar situations can exist with every *object*, that can be manipulated from multiple threads at the same time. In so far I cannot see how a *function* ever can be documented to be "thread safe" in general.

IMO it would be much more interesting to document, which operations (functions, objects...) can be used in parallel threads, and how these can/must be protected for that purpose.

After all: how/where can I find thread-related Lazarus/FPC documentation? My wiki search was not really successful :-(

DoDi

Reply by email

Mattias Gaertner
to Hans-Peter Diettrich
Show quoted text 6 lines
Mattias Gaertner schrieb: > Only if the documentation explicitly says a method is thread safe it is. > Maybe this needs to be made more clear. Any ideas, where? What is "thread safe"?

http://lmgtfy.com/?q=thread+safe&l=1

A piece of code is "thread safe" if it can be safely invoked by multiple threads at the same time.

[...] After all: how/where can I find thread-related Lazarus/FPC documentation? My wiki search was not really successful :-(

What words did you search?
I got results on Thread, Threads and Multithreading.

Mattias

Reply by email

Michael Schnell
to Hans-Peter Diettrich: What is "thread safe"? In how far is just FileExistsUTF8 "thread safe"? Even if the file…
Hans-Peter Diettrich wrote
What is "thread safe"?

IMHO, quite often, this needs further explanation in the docs.

e.g. if the code in question defines a class the diversification is generated by the potential use of class variables and global variables:

- Are you allowed to create in in another thread but the main thread (e.g. forbidden for GUI-aware objects) ?

- Can you create the class in one thread and call it's functions and properties from another one (e.g. forbidden for GUI-aware objects) ?

- Are the functions and properties of a single project reentry-safe (is it allowed to use the same function of the same instance with multiple threads).

- Is it allowed to use multiple instances of the object with multiple threads (each thread uses an instance; is it allowed to use the same function of a different instance with multiple threads).

- Does an instance internally create threads and are events thrown in the context of such a thread instead in the context of the thread that created the object ?

- ...

-Michael

Reply by email

Michael Schnell
to Krzysztof: Huh, 35 new messages in my topic :) . After reading all, maybe I summarize why I need…
Krzysztof wrote
So, I wrote TMyHTTPClient which is some kind of layer for synapse http client

AsyncPro is a good example for something like this:

An instance of an APRO Object (that handles either an asynchronous or a TCP/IP-Socket based bidirectional stream) internally creates threads that are assigned to the blocking in and out API functions of the OS.

Mechanisms like that we have been discussing here, are used to make the interface of the object completely un-threaded (and with that thread-safe). There are event properties, and the functions defined there are called in the context of the main thread when an internal worker thread schedules the event. Data is provided to theses event handlers in a thread-safe manner.

Multiple requests in this forum and elsewhere suggest that Lazarus would benefit a lot from an Async-Pro port or work-alike, being part of the packet.

Maybe you can do your project in a way that in a versatile way implements the core of this: a class that creates internal "in" and "out" threads and provides hooks for attaching a blocking interface of any kind of byte-stream to same.

The now bug-free Application.QueueAsyncCall() should be the perfect thread-transfer-mechanism.

Only downside: AFAIK, right now it is not possible to create a Lazarus Application that has no GUI binding and provides a working Application.QueueAsyncCall() and TTimers that would allow you to easily react on timeouts in the communication you are monitoring. So you supposedly need to do a GTK2, QT, or Windows application.

-Michael

Reply by email

Hans-Peter Diettrich
to Mattias Gaertner: On Fri, 10 Jun 2011 03:09:07 +0200 http://lmgtfy.com/?q=thread+safe&l=1 A piece of code…
Show quoted text 8 lines
>> Only if the documentation explicitly says a method is thread safe it is. >> Maybe this needs to be made more clear. Any ideas, where? > What is "thread safe"? http://lmgtfy.com/?q=thread+safe&l=1 A piece of code is "thread safe" if it can be safely invoked by multiple threads at the same time.

As already explained, I'm not comfortable with that definition.

Which aspect would cover access to shared objects by different "pieces of code"?

Show quoted text 6 lines
> [...] > After all: how/where can I find thread-related Lazarus/FPC > documentation? My wiki search was not really successful :-( What words did you search? I got results on Thread, Threads and Multithreading.

Yes, hundreds of results per search - this is not really helpful :-(

It would help, to some degree, if a language could be specified, so that the results are not crowded with any number of translated pages.

DoDi

Reply by email

Henry Vermaak
to Hans-Peter Diettrich: What is "thread safe"? In how far is just FileExistsUTF8 "thread safe"? Even if the file…
Hans-Peter Diettrich wrote
What is "thread safe"?

The definition is very clear here:

http://en.wikipedia.org/wiki/Thread_safety

In how far is just FileExistsUTF8 "thread safe"? Even if the file existed at function return, it can have been killed by somebody else immediately after, even from outside the application.

This example is here:

http://en.wikipedia.org/wiki/Thread_safety#Concurrent_programing

It has nothing to do with thread safety.

Henry

Reply by email

Mattias Gaertner
to Hans-Peter Diettrich: As already explained, I'm not comfortable with that definition. Which aspect would cover…
Show quoted text 12 lines
Mattias Gaertner schrieb: >>> Only if the documentation explicitly says a method is thread safe it is. >>> Maybe this needs to be made more clear. Any ideas, where? >> What is "thread safe"? > > http://lmgtfy.com/?q=thread+safe&l=1 > > A piece of code is "thread safe" if it can be safely invoked by > multiple threads at the same time. As already explained, I'm not comfortable with that definition.

Welcome to earth. How do you define it on your planet?

Which aspect would cover access to shared objects by different "pieces of code"?

What did you not understand on the link I gave?

Show quoted text 8 lines
>> [...] >> After all: how/where can I find thread-related Lazarus/FPC >> documentation? My wiki search was not really successful :-( > > What words did you search? > I got results on Thread, Threads and Multithreading. Yes, hundreds of results per search - this is not really helpful :-(

I'm always amazed how spoiled Lazarus users are. I think this is a compliment for Lazarus. :)

It would help, to some degree, if a language could be specified, so that the results are not crowded with any number of translated pages.

+1

Although I must admit I would not use that feature, because I often want to know where a word is used.

Mattias

Reply by email

Michael Schnell
to Henry Vermaak: The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety This…
Henry Vermaak wrote 8 lines
On 10/06/11 02:09, Hans-Peter Diettrich wrote: > > What is "thread safe"? The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety

clear does not imply useful :) .

With "piece of code" they obviously mean a single function (or part of it), with the implication that no other functions are called during this test by any of those threads.

E.g. Regarding Objects this is not enough.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 14 lines
On 06/10/2011 01:26 PM, Henry Vermaak wrote: > On 10/06/11 02:09, Hans-Peter Diettrich wrote: >> >> What is "thread safe"? > > The definition is very clear here: > > http://en.wikipedia.org/wiki/Thread_safety > clear does not imply useful :) . With "piece of code" they obviously mean a single function (or part of it), with the implication that no other functions are called during this test by any of those threads.

?
Of course a threads safe function can call other thread safe functions.

E.g. Regarding Objects this is not enough.

Prove?

Mattias

Reply by email

Michael Schnell
to Mattias Gaertner
Mattias Gaertner wrote
> E.g. Regarding Objects this is not enough. Prove?

Theory: with multiple instances, the same "piece of code" behaves differently, according to to the states that are stored internally in an instance.

It's not practical to just ignore this as a specification: you now would need to say that Objects never are thread safe and by this make any object language totally unsuited for threaded application.

It's a lot more helpful to do a more sophisticated definition of thread-safety for objects.

Example:

Imagine you create an instance of an object for each thread.

So the same "piece of code" (a function procedure or property of the object) can behave differently regarding which instance is used (here which thread is calling it).

e.g. the function accesses just class variables (and local variables). Now it is thread safe if in fact each thread uses it's instance; but it's not thread safe, if a thread uses another thread's instance.

If it uses global variables it is not thread

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 7 lines
On 06/10/2011 02:18 PM, Mattias Gaertner wrote: >> E.g. Regarding Objects this is not enough. > Prove? Theory: with multiple instances, the same "piece of code" behaves differently, according to to the states that are stored internally in an instance.

Not only theory. It's common practical thing. For example TThreadList.Add is thread safe and each call changes the object.

It's not practical to just ignore this as a specification: you now would need to say that Objects never are thread safe and by this make any object language totally unsuited for threaded application.

I can't follow you here.

Show quoted text 15 lines
It's a lot more helpful to do a more sophisticated definition of thread-safety for objects. Example: Imagine you create an instance of an object for each thread. So the same "piece of code" (a function procedure or property of the object) can behave differently regarding which instance is used (here which thread is calling it). e.g. the function accesses just class variables (and local variables). Now it is thread safe if in fact each thread uses it's instance; but it's not thread safe, if a thread uses another thread's instance.

I got the feeling you are not familiar with mathematical definitions. If the definition says "it can be safely invoked by multiple threads at the same time" then it means it can be invoked by any thread in any order at any time and the code still performs its task.

For example:
TThreadList.Add is thread safe because the task is to add an element to the list.
If you define the task that after calling the element is in the list, then it would not be thread safe.

If it uses global variables it is not thread example the heap manager uses global variables and it is

thread safe.

Mattias

Reply by email

Michael Schnell
to Mattias Gaertner
Mattias Gaertner wrote
If the definition says "it can be safely invoked by multiple threads at the same time" then it means it can be invoked by any thread in any order at any time and the code still performs its task.

But what is "it".

The wiki says: "piece of code". With Objects this would need to be "piece of code of a particular instance", as the same "piece of code" of another instance c an behave totally different, as the states that are stored in the instance can behave totally different.

Of course (only with less practical value) this is also true in a not-object languages:

The "piece of code" can be a function that is called with a parameter. It can be thread safe if each thread calls it with a different parameter value (say a number denoting the thread) and not thread safe if some threads call it with the same parameter.

e.g.:

void a(n) {

   array[n] ++;

}

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 7 lines
On 06/10/2011 03:32 PM, Mattias Gaertner wrote: > > If the definition says "it can be safely invoked by multiple threads at > the same time" then it means it can be invoked by any thread in any order at any time and the code still performs its task. But what is "it". The wiki says: "piece of code".

correct

With Objects this would need to be "piece of code of a particular instance",

No.

as the same "piece of code" of another instance c an behave totally different, as the states that are stored in the instance can behave totally different.

Doesn't matter as long the code does its task.

[...]

Mattias

Reply by email

Michael Schnell
to Reimar Grabowski
Reimar Grabowski wrote
> threads call it with the same parameter. These kind of functions are called not thread safe.

That is exactly what I wanted to say. (With Objects this is more obscure than with the ANSI C code example, as the instance parameter is hidden and the application programmer usually is not aware if same.)

Regarding objects this definition does not make much senses, as this would make make most objects non thread safe, while they would be thread-safe if each thread uses it's dedicated instance.

Thus a more sophisticated definition of thread safety for objects makes a lot more sense that simply stating that practically all objects are not thread safe, even though the practical use of a class could be to be have an instance used by a single thread.

e.g. TList:

TThreadList is "completely thread safe".

TList is (supposedly) "per-instance thread safe": the "TThread.Add" "piece of code" can happily be used by multiple threads at the same time, as long as each thread uses a different instance. I suppose this is done quite often.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 7 lines
On 06/10/2011 04:01 PM, Reimar Grabowski wrote: > > The "piece of code" can be a function that is called with a parameter. > > It can be thread safe if each thread calls it with a different parameter > > value (say a number denoting the thread) and not thread safe if some > > threads call it with the same parameter. > These kind of functions are called not thread safe. That is exactly what I wanted to say.

No.
Whether a function is "thread safe" does not depend on how you call it. If a function can fail if it is called with wrong parameters or by the wrong Thread, then it is as Reimar wrote: it is not thread safe.

And now follows a lot of text, how to safely call not thread safe functions, which might have been useful on a forum for parallel programming, if it would not invent misleading terms like "completely thread safe":

Show quoted text 21 lines
(With Objects this is more obscure than with the ANSI C code example, as the instance parameter is hidden and the application programmer usually is not aware if same.) Regarding objects this definition does not make much senses, as this would make make most objects non thread safe, while they would be thread-safe if each thread uses it's dedicated instance. Thus a more sophisticated definition of thread safety for objects makes a lot more sense that simply stating that practically all objects are not thread safe, even though the practical use of a class could be to be have an instance used by a single thread. e.g. TList: TThreadList is "completely thread safe". TList is (supposedly) "per-instance thread safe": the "TThread.Add" "piece of code" can happily be used by multiple threads at the same time, as long as each thread uses a different instance. I suppose this is done quite often.

Please read a book about parallel programming.

Mattias

Reply by email

Michael Schnell
to Mattias Gaertner
Mattias Gaertner wrote
Please read a book about parallel programming.

Not necessary. I don't argue about the technical implications of thread programming and code sequences.

This is just a matter of wording. I do believe that we both know about the technology in question. So lets just invent another term instead of "thread safe" that can be defined in a way that it does make sense with Objects. :)

.Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 10 lines
On 06/10/2011 04:59 PM, Mattias Gaertner wrote: > > Please read a book about parallel programming. Not necessary. I don't argue about the technical implications of thread programming and code sequences. This is just a matter of wording. I do believe that we both know about the technology in question. So lets just invent another term instead of "thread safe" that can be defined in a way that it does make sense with Objects. :)

Sigh. It already does. See my TThreadList.Add example.

If you need a term for a method with less thread safety you might look for reentrant or thread local.

Mattias

Reply by email

Hans-Peter Diettrich
to Mattias Gaertner: On Fri, 10 Jun 2011 12:49:59 +0200 Welcome to earth. How do you define it on your planet?…
Show quoted text 5 lines
>> A piece of code is "thread safe" if it can be safely invoked by >> multiple threads at the same time. > As already explained, I'm not comfortable with that definition. Welcome to earth. How do you define it on your planet?

My planet government decided to use objects, in addition to "pieces of code", decades ago :-]

> Which aspect would cover access to shared objects by different "pieces > of code"? What did you not understand on the link I gave?

How objects fit into that non-OO definition.

DoDi

Reply by email

Hans-Peter Diettrich
to Henry Vermaak: The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety This…
Show quoted text 5 lines
> What is "thread safe"? The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety

It is not really clear:

"A piece of code is thread-safe if it can be safely invoked by multiple threads at the same time".

Which piece of code can *not* be "safely invoked"?

Instead I'd define "thread safety" as the *absence* of possible data or state inconsistencies in concurrent execution [of threads].

As mentioned in most articles "It is not easy to determine if a piece of code is thread-safe or not". That's why I wonder how a subroutine (piece of code) can be said to be thread-safe, without indicating the really asserted behaviour and possible limitations.

E.g. QueueAsyncCall may be "safely invoked", but what will happen later, when e.g. the referenced object is destroyed prior to the according Deque? The caller will never be notified of the outcome of the call! How can the caller check, after posting an call, that the operation has executed or has been dropped? When will it be *safe* to release the Data object, that possibly has been passed to the callee? That's why I'm missing at least a note, that the queued call may never execute, and that passing pointers for Data is unsafe.

Okay, it may be beyond the scope of QueueAsyncCall, to establish means for synchronization between the caller and the callee. But what could be done to allow for such synchronization?

DoDi

Reply by email

Hans-Peter Diettrich
to Mattias Gaertner: On Fri, 10 Jun 2011 16:17:15 +0200 No. Whether a function is "thread safe" does not…
Whether a function is "thread safe" does not depend on how you call it. If a function can fail if it is called with wrong parameters or by the wrong Thread, then it is as Reimar wrote: it is not thread safe.

I dare to disagree. When a procedure call can fail in a single-threaded environment, for some reason, then it is allowed to fail in a multi-threaded environment as well. It's up to the function to return an appropriate error code - this doesn't make the procedure thread-unsafe.

And now follows a lot of text, how to safely call not thread safe functions, which might have been useful on a forum for parallel programming, if it would not invent misleading terms like "completely thread safe"

That's why I'd classify procedures as *immanently* thread-safe, when they don't rely on unsafe shared data (objects...), or as protected against *certain* threading issues. The rest will stay "unknown", or can have a list of *known* threading (or reentrancy...) issues.

Objects are much harder to classify, because only few of them are designed with only thread-safe public methods. Nonetheless it would be interesting to know, which objects (classes) can be used safely when *encapsulated* in an thread [created by the thread, no references passed to or ending up in other threads]. Obviously all event handlers and other notification callbacks, stored in an object, can violate this requirement.

DoDi

Reply by email

Marco van de Voort
to Hans-Peter Diettrich: It is not really clear: "A piece of code is thread-safe if it can be safely invoked by…
Hans-Peter Diettrich wrote 6 lines
threads at the same time". Which piece of code can *not* be "safely invoked"? Instead I'd define "thread safety" as the *absence* of possible data or state inconsistencies in concurrent execution [of threads].

The FileExistsUTF8() definition even adheres to that. The possible inconsistency is in a different layer, the OS layer outside the runtime and language's reach.

In short, then you must simply open the file for exclusive access and abort on failure to open, instead of checking for existance.

Reply by email

Bart
to Erwin van den Bosch

Please define "does not work" and "looks weird" (attach screenshot perhaps).

Same problem exist with trunk?

Bart

Erwin van den Bosch wrote 18 lines
TDBGrid does look weird and doesn't function anymore in svn: branches/fixes_0_9_30 Revision 31056 does work. Revision 31057 doesn't :-( fpc 2.4.2 Opensuse 11.2 x64 lazarus compiled for QT Regard, Erwin -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Erwin van den Bosch
to Bart
Bart wrote
Please define "does not work" and "looks weird" (attach screenshot perhaps).

Can't you reproduce it?

#DEFINE Does_not_work = Does not grid lines. No header. Nothing.

I can attach a screenshot but if you can't reproduce it a screenshot will not help too. Have you test it?
It happens on Linux with QT.

Same problem exist with trunk?

I don't know. I'm on the stable branch.

Regards,
Erwin.

Show quoted text 26 lines
Bart On 6/13/11, Erwin van den Bosch wrote: > TDBGrid does look weird and doesn't function anymore in svn: > branches/fixes_0_9_30 > > Revision 31056 does work. Revision 31057 doesn't :-( > > fpc 2.4.2 > Opensuse 11.2 x64 > lazarus compiled for QT > > Regard, > Erwin > > -- > _______________________________________________ > Lazarus mailing list > > http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus > -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110613/d73638f0/attachment.html>

Reply by email

zeljko
to Erwin van den Bosch
Erwin van den Bosch wrote 16 lines
Op 13-06-11 00:32, Bart schreef: > Please define "does not work" and "looks weird" (attach screenshot > perhaps). Can't you reproduce it? #DEFINE Does_not_work = Does not grid lines. No header. Nothing. I can attach a screenshot but if you can't reproduce it a screenshot will not help too. Have you test it? It happens on Linux with QT. > Same problem exist with trunk? I don't know. I'm on the stable branch.

Just dropped an TDBGrid onto form and it looks ok (trunk lazarus).

zeljko

Reply by email

Erwin van den Bosch
to zeljko
zeljko wrote
Same problem exist with trunk? > I don't know. I'm on the stable branch. Just dropped an TDBGrid onto form and it looks ok (trunk lazarus).

Zeljko, have you tested the fixes branch? I'm on the fixes branch. I will test the trunk tree today. (First some coffee)

Regards,
Erwin

Reply by email

Erwin van den Bosch
to Erwin van den Bosch
Erwin van den Bosch wrote 7 lines
Op 13-6-2011 8:06, zeljko schreef: > Same problem exist with trunk? >> I don't know. I'm on the stable branch. > Just dropped an TDBGrid onto form and it looks ok (trunk lazarus). > Zeljko, have you tested the fixes branch? I'm on the fixes branch. I will test the trunk tree today. (First some coffee)

Just checked it on the trunk tree. And it looks good. No problem. Just for sure I checked out a fresh clean fixes branch and there the problem was again.
Looks like a painting problem in TDBGrid. Maybe something went wrong with an svnmerge
on the branch fixes_0_9_30?

So it seems you have to checkout the fixes branch to see this bug.

Regards,
Erwin.

Reply by email

zeljko
to Erwin van den Bosch
Erwin van den Bosch wrote 17 lines
Op 13-06-11 08:46, Erwin van den Bosch schreef: > Op 13-6-2011 8:06, zeljko schreef: >> Same problem exist with trunk? >> >>> I don't know. I'm on the stable branch. >> >> Just dropped an TDBGrid onto form and it looks ok (trunk lazarus). > > Zeljko, have you tested the fixes branch? I'm on the fixes branch. > I will test the trunk tree today. (First some coffee) Just checked it on the trunk tree. And it looks good. No problem. Just for sure I checked out a fresh clean fixes branch and there the problem was again. Looks like a painting problem in TDBGrid. Maybe something went wrong with an svnmerge on the branch fixes_0_9_30?

Don't know, no time to test fixes_0_9_30 atm ...

z.

Reply by email

Erwin van den Bosch
to zeljko
zeljko wrote
Don't know, no time to test fixes_0_9_30 atm ... z.

I compared the file lcl/interfaces/qt/qtwinapi.inc in fixes_0_9_30 with the one in trunk.

Find a few lines of code that wasn't in the trunk tree.

Fixed the bug in the attached patch.

Regards,
Erwin.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: qtwinapi.patch
Type: text/x-patch
Size: 509 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110613/4b1edaf6/attachment.bin>

Reply by email

zeljko
to Erwin van den Bosch
Erwin van den Bosch wrote 11 lines
Op 13-06-11 12:40, zeljko schreef: > Don't know, no time to test fixes_0_9_30 atm ... > > z. I compared the file lcl/interfaces/qt/qtwinapi.inc in fixes_0_9_30 with the one in trunk. Find a few lines of code that wasn't in the trunk tree. Fixed the bug in the attached patch.

Thanks for searching, r30608 should be merged in that case.I'll inform Juha about this.

zeljko

Reply by email

Michael Schnell
to Mattias Gaertner: On Fri, 10 Jun 2011 17:58:44 +0200 Sigh. It already does. See my TThreadList.Add example.…
Mattias Gaertner wrote
Sigh. It already does. See my TThreadList.Add example.

This example shows that it does not make sense.

(Supposedly) TThreadList.Add is "separate-instance-thread safe" (each thread can create an instance and use the "Add" procedure without risking a conflict).

TThreadList.Add is not "cross-instance-thread safe" (multiple threads using the same instance's "Add" procedure will result in erroneous behavior).

Simply stating that TThreadList.Add is "not thread save" (which of course is perfectly correct) would prevent using a TThreadList as a data store e.g. in a thread class that itself is instantiated multiple times. There using TThreadList would be overkill.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 8 lines
On 06/10/2011 06:09 PM, Mattias Gaertner wrote: > > Sigh. It already does. See my TThreadList.Add example. This example shows that it does not make sense. (Supposedly) TThreadList.Add is "separate-instance-thread safe" (each thread can create an instance and use the "Add" procedure without risking a conflict). TThreadList.Add is not "cross-instance-thread safe" (multiple threads using the same instance's "Add" procedure will result in erroneous behavior).

Why do you think so?

Simply stating that TThreadList.Add is "not thread save" (which of course is perfectly correct) would prevent using a TThreadList as a data store e.g. in a thread class that itself is instantiated multiple times. There using TThreadList would be overkill.

Mattias

Reply by email

Henry Vermaak
to Michael Schnell: This example shows that it does not make sense. (Supposedly) TThreadList.Add is…
Michael Schnell wrote 8 lines
On 06/10/2011 06:09 PM, Mattias Gaertner wrote: > > Sigh. It already does. See my TThreadList.Add example. This example shows that it does not make sense. (Supposedly) TThreadList.Add is "separate-instance-thread safe" (each thread can create an instance and use the "Add" procedure without risking a conflict).

Everything is "separate-instance-thread safe". How can something be unsafe if only one thread is accessing it?

TThreadList.Add is not "cross-instance-thread safe" (multiple threads using the same instance's "Add" procedure will result in erroneous behavior).

No, it won't. All the operations lock the list, so you can use the same instance from multiple threads. Just read the source before you make misguided comments like this.

Henry

Reply by email

Michael Schnell
to Mattias Gaertner: On Tue, 14 Jun 2011 11:53:14 +0200 Why do you think so? Mattias
Mattias Gaertner wrote
Why do you think so?

Sorry I have been typing much faster than thinking here (again). I had meant to be talking about TTlist. :-[ :-[ :-[

So once again:

------------------------------------------------------------------------

(Supposedly) TList.Add is "separate-instance-thread safe" (each thread can create an instance and use the "Add" procedure without risking a conflict).

TList.Add is not "cross-instance-thread safe" (multiple threads using the same instance's "Add" procedure will result in erroneous behavior).

Simply stating that TList.Add is "not thread save" (which of course is perfectly correct) would prevent using a TList instance as a data store e.g. in a thread class that itself is instantiated multiple times. There using TThreadList would be overkill.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110614/6235283f/attachment.html>

Reply by email

Michael Schnell
to Henry Vermaak: Everything is "separate-instance-thread safe". How can something be unsafe if only one…
Everything is "separate-instance-thread safe". How can something be unsafe if only one thread is accessing it?

As soon as you use global variables. E.G. "Application" uses global variables, as well internally, as implicitly by doing calls to an external Widget set. That is why the LCL is known to be "not thread safe".

Show quoted text 6 lines
> TThreadList.Add is not "cross-instance-thread safe" (multiple threads > using the same instance's "Add" procedure will result in erroneous > behavior). No, it won't.

Right you are. I meant to write TList". Sorry.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell: Sorry I have been typing much faster than thinking here (again). I had meant to be…
On 06/14/2011 12:02 PM, Mattias Gaertner wrote: > Why do you think so? Sorry I have been typing much faster than thinking here (again). I had meant to be talking about TTlist. :-[ :-[ :-[

Your mails contain so many confusions - "TThread.Add", "completely thread safe", "separate-instance-thread safe", TList with TThreadList and now "TTlist". You are a very confused troll. This thread started about "thread safe" LCL functions. If you want that FCL functions/methods be documented whether they are thread safe or not you can ask on the fpc lists or create a feature request.

Show quoted text 5 lines
[...] Simply stating that TList.Add is "not thread save" (which of course is perfectly correct) would prevent using a TList instance as a data store e.g. in a thread class that itself is instantiated multiple times. There using TThreadList would be overkill.

Mattias

Reply by email

Michael Schnell
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote
How would you expect a thread-safe version to work? A TList doesn't serialize requests, this would have to be added separately.

It does not need to, as "separate-instance-thread safe" means that each thread handles only it's own instance.

"Add" only needs to use stack variables and instance variables. Both are dedicated to the thread and thus don't need a protection (OK it if needs to allocate memory the heap allocation procedure does need protection mechanism, but this is provided by the infrastructure anyway. )

-Michael

Reply by email

Malcom Haak
to Michael Schnell

Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using Critical Sections before doing work. In some code I have seen before a critical section was entered before calling TList.Add
Now provided that you don't need a specific order, does this not then make it thread safe?

Michael Schnell wrote 23 lines
On 06/14/2011 04:57 PM, Hans-Peter Diettrich wrote: > > How would you expect a thread-safe version to work? A TList doesn't > serialize requests, this would have to be added separately. > > It does not need to, as "separate-instance-thread safe" means that each thread handles only it's own instance. "Add" only needs to use stack variables and instance variables. Both are dedicated to the thread and thus don't need a protection (OK it if needs to allocate memory the heap allocation procedure does need protection mechanism, but this is provided by the infrastructure anyway. ) -Michael -- ______________________________**_________________ Lazarus mailing list .**freepascal.org http://lists.lazarus.**freepascal.org/mailman/**listinfo/lazarus<http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110623/d8efe4bb/attachment.html>

Reply by email

Hans-Peter Diettrich
to Malcom Haak
Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using Critical Sections before doing work. In some code I have seen before a critical section was entered before calling TList.Add

IMO this won't help, because any other thread that does *not* use the critical section still can trash the list.

It might help when TList.Add would use a critical section internally, but then *all* lists are blocked at once, unless a critical section is connected to *every* single TList instance - what may run into out-of-resources. Otherwise a global TList.Add lock may lock up an entire application, when an OnAdd handler tries to use another (temporary...) TList.

IMO. I may be wrong here, because I used threads only on realtime systems, never in Delphi or Lazarus...

BTW, I just got my copy of RAD Studio XE, where e.g. thread.suspend is deprecated, and other means for thread synchronization are added. But these have to be implemented in FPC first, before SpinLock or other procedures or methods can be used.

DoDi

Reply by email

Andrew Brunner
to Malcom Haak: Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using…

2011/6/22 Malcom Haak :

Show quoted text 7 lines
Correct me if I'm wrong, But can't you technically make any code 'thread-safe' ?by using Critical Sections before doing work. In some code I have seen before a critical section was entered before calling TList.Add Now provided that you don't need a specific order, does this not then make it thread safe?

Partially. Read barriers may not be necessary. It depends on the implementation. By having barriers placed at strategic locations in the code, you can make an implementation thread safe.

Add, Delete, and Clear would be some. List iterations would be difficult if not unsafe outside a lock but if accessed under a manager thread you can schedule and operation and it will wait done until conditions are safe to perform.

Getting an item from the list rather than locking the entire list and having an inUse boolean set to true for that item, would allow for any deletion to be blocked until another time (by a manager thread).

With multi-core systems simply adding a mutex/lock is not enough. A manager is needed to be in place to safely provision, delegate, and use items. IMO, this forces efficiency in a system design. The basic logic for a manager thread is that the manager thread is accepting commands, and scheduled execution happens automatically.

Further, you could create a command system for each list so when you add/remove an item from the list you are merely scheduling that item for deletion. I would avoid polling for large lists. The command should have a completion routine like Item.onComplete(Item) where the item is passed for use in the application.

This way there would be absolutely no waiting for data in code and the system in general at rest until needed.

Reply by email

Michael Schnell
to Malcom Haak: Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using…
Malcom Haak wrote
Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using Critical Sections before doing work.

Of course you are correct. But this is not a decent way to go.
1) the calls of CriticalSection themselves can slow down the code, as they need library and (unless the Library and the Arch decently implements FUTEX) System API calls. And even with FUTEX, hardware-locked instructions need to be use that might count for hundreds of normal instructions with modern processors due to necessary cache syncing.
2) if the CriticalSection in fact requires waiting the increase in latency is huge. So the calls should be placed only there where they are really necessary and the code should be optimized to run as little within CriticalSections as possible.

In some code I have seen before a critical section was entered before calling TList.Add Now provided that you don't need a specific order, does this not then make it thread safe?

Yes, but in General it's not a decent way to go.

That is why I state that TList (supposedly) already is "per-instance thread safe" and does not need further ado if no concurrent thread accesses the same instance.

-Michael

Reply by email

Michael Schnell
to Hans-Peter Diettrich: IMO this won't help, because any other thread that does *not* use the critical section…
Hans-Peter Diettrich wrote
I may be wrong here, because I used threads only on realtime systems, never in Delphi or Lazarus...

Threads can help to greatly improve the soft realtime behavior of a Delphi/Lazarus program. We do this a lit.

Show quoted text 6 lines
BTW, I just got my copy of RAD Studio XE, where e.g. thread.suspend is deprecated, and other means for thread synchronization are added. But these have to be implemented in FPC first, before SpinLock or other procedures or methods can be used.

IMHO TThread.Suspend and friends is a very queer way of doing thread synchronizing. The Delphi developers seem to have been drunk when inventing this (in vain trying to create something idiot-friendly). I never used this stuff.

-Michael

Reply by email

Marco van de Voort
to Hans-Peter Diettrich: IMO this won't help, because any other thread that does *not* use the critical section…
Hans-Peter Diettrich wrote
BTW, I just got my copy of RAD Studio XE, where e.g. thread.suspend is deprecated,

So is FPC 2.4.4.

and other means for thread synchronization are added.

???? Afaik they only added "start" as a replacements for deprecated .resume.

But these have to be implemented in FPC first, before SpinLock or other procedures or methods can be used.

These are afaik unrelated to the above change, and related to the addition of monitors.

Reply by email

Michael Schnell
to Andrew Brunner: 2011/6/22 Malcom Haak : Partially. Read barriers may not be necessary. It depends on the
Andrew Brunner wrote
With multi-core systems simply adding a mutex/lock is not enough.

A MUTEX or FUTEX (or CriticalSection) is supposed to work as expected on multi-Core systems as well. User code is not supposed to need to bother about running on a multi-core system. If MUTEX/FUTEX does not work correctly this is a bug of the OS / SystemLibrary.

-Michael

Reply by email

Unknown author
to Michael Schnell: Threads can help to greatly improve the soft realtime behavior of a Delphi/Lazarus…
Michael Schnell wrote 15 lines
On 06/23/2011 07:50 AM, Hans-Peter Diettrich wrote: > I may be wrong here, because I used threads only on realtime systems, never > in Delphi or Lazarus... Threads can help to greatly improve the soft realtime behavior of a Delphi/Lazarus program. We do this a lit. > > BTW, I just got my copy of RAD Studio XE, where e.g. thread.suspend is > deprecated, and other means for thread synchronization are added. But these > have to be implemented in FPC first, before SpinLock or other procedures or > methods can be used. > IMHO TThread.Suspend and friends is a very queer way of doing thread synchronizing. The Delphi developers seem to have been drunk when inventing this (in vain trying to create something idiot-friendly). I never used this stuff.

These calls are simply wrappers around the Microsoft threading API. So it's the MS engineers who were drunk, I suppose.

Michael.

Reply by email

Martin
to Malcom Haak: Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using…
Malcom Haak wrote
Correct me if I'm wrong, But can't you technically make any code 'thread-safe' by using Critical Sections before doing work.

I don't think so.

If the function, for example stores some important data in a thread local variable, but flags (thread global) the availability of the data, then no Critical section will fix it.

Admittedly this is a constructed case, and sounds like an extremely poor implementation... But it shows that thread-safety is more than just a Critical Section. After execution of a thread-save function the overall state of your app (and the entire system) must still be valid (and it must be so, for each thread).

Martin

Reply by email

Michael Schnell
to Martin: I don't think so. If the function, for example stores some important data in a thread…
Martin wrote 5 lines
If the function, for example stores some important data in a thread local variable, but flags (thread global) the availability of the data, then no Critical section will fix it.

Yep !

As stated in my former messages in this thread, IMHO, the "official" definition of thread-safe-ness does not make much sense with objects, but a more complex definition covering several cases of use is necessary.

-Michael

Reply by email

Martin
to Michael Schnell
Michael Schnell wrote 11 lines
On 06/27/2011 11:37 AM, Martin wrote: > > If the function, for example stores some important data in a thread > local variable, but flags (thread global) the availability of the > data, then no Critical section will fix it. > Yep ! As stated in my former messages in this thread, IMHO, the "official" definition of thread-safe-ness does not make much sense with objects, but a more complex definition covering several cases of use is necessary.

Why? Where does the definition conflict with the above? "A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the same time"

"Save invocation" includes that the function returns a "correct" result(output) for any "input".

Where "input":
- is not limited to the parameters passed in the parameter list, not even to limited to parameters passed implicitly (such as the object instance)
- input includes the entire state of the system (that can be global vars, available and unavailable resources of any kind, and much more) The same applies to "result", or "output".

This part of "Save invocation" is not limited to thread safeness. It applies to any piece of code.
For example, a piece of code involving memory allocation, must examine the result of the actual "AllocMem" call for errors. Otherwhise it is not save to be executed, as it may fail with an undefined result, if no mem is available.

So as far as I can see, my example, (as well as objects) are very well covered by the definition.

Martin

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/cb039689/attachment.html>

Reply by email

Martin
to Martin
Martin wrote 20 lines
On 27/06/2011 11:19, Michael Schnell wrote: > On 06/27/2011 11:37 AM, Martin wrote: >> >> If the function, for example stores some important data in a thread >> local variable, but flags (thread global) the availability of the >> data, then no Critical section will fix it. >> > Yep ! > > As stated in my former messages in this thread, IMHO, the "official" > definition of thread-safe-ness does not make much sense with objects, > but a more complex definition covering several cases of use is > necessary. Why? Where does the definition conflict with the above? "A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the same time" "Save invocation" includes that the function returns a "correct" result(output) for any "input".

Make that "any defined/allowed" input

Obviously if you pass in a pointer to random memory as object instance no function will be ave to call.

Show quoted text 8 lines
Where "input": - is not limited to the parameters passed in the parameter list, not even to limited to parameters passed implicitly (such as the object instance) - input includes the entire state of the system (that can be global vars, available and unavailable resources of any kind, and much more) The same applies to "result", or "output".

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/bf346813/attachment.html>

Reply by email

Lukasz Sokol
to Michael Schnell: Yep ! As stated in my former messages in this thread, IMHO, the "official" definition of…
Michael Schnell wrote 14 lines
On 06/27/2011 11:37 AM, Martin wrote: > > If the function, for example stores some important data in a thread > local variable, but flags (thread global) the availability of the > data, then no Critical section will fix it. > Yep ! As stated in my former messages in this thread, IMHO, the "official" definition of thread-safe-ness does not make much sense with objects, but a more complex definition covering several cases of use is necessary. -Michael

The computer/OS/system has no clue of anything you may call 'an object'... when compiled, it is just 'code'.

OOP is just a convenient abstraction, it's for people needed only :)

L.

Reply by email

Michael Schnell
Martin wrote
Why? Where does the definition conflict with the above? "A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the same time"

It does not *conflict* it is just not useful.

The problem is not "safe invocation" the problem is "*a* piece of code".

An object is invocated with a hidden self pointer. So for the "user" this "self" is not an "input" as normal parameters are.

By definition, an object is a combination of a data store and a pool of functions.

Thus (when looking at your definition above) you either can define that (A) the the "code" is *different* for multiple instances of the object (even though it only exists once in memory and in the source code), or you can define or you can define that (B) it's *the same piece of code* for all instances.

From the point of view of the user both does make sense (if you get him to be aware of that at all).

Obviously as an example, the (non-thread-safe) TList.add (supposedly) can happily be used with multiple threads if each thread uses it's own instance and thus different code (regarding definition (A), while TThreadList is thread safe (regarding both definitions) and the same instance can be used by multiple threads.

The reason is, that TList just uses (stack and) class variables (and decently protected global variables), While with TThreadList additionally the class variables are decently protected.

OTOH, e.g. TForm is not thread save at all: you can't do multiple instances and use each of them from it's dedicated thread, because implicitly TForm uses unprotected global variables.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/31ef0af2/attachment.html>

Reply by email

Michael Schnell
to Lukasz Sokol: The computer/OS/system has no clue of anything you may call 'an object'... when compiled,…
Lukasz Sokol wrote
The computer/OS/system has no clue of anything you may call 'an object'... when compiled, it is just 'code'.

Yep.

But before compiling this is different from the "user" 's point of view: he does not see (and in most cases should not be aware of) the hidden self pointer that technically is an input to the "piece of code" but is not visible in the source code of an object-language.

Thus the increased complexity.

-Michael

Reply by email

Martin
to Michael Schnell: It does not *conflict* it is just not useful. The problem is not "safe invocation" the…
Michael Schnell wrote 11 lines
On 06/27/2011 12:51 PM, Martin wrote: > > Why? Where does the definition conflict with the above? > "A piece of code is *thread-safe* if it can be safely invoked by > multiple threads at the same time" It does not *conflict* it is just not useful. The problem is not "safe invocation" the problem is "*a* piece of code". An object is invocated with a hidden self pointer. So for the "user" this "self" is not an "input" as normal parameters are.

Unfortunately you left out the real important part of my last msg.

If you choose to ignore the full meaning of "safely invoked " (even WITHOUT threads), then I agree the definition is not useful. But then which definition is useful if you ignore parts of it?

Ask yourself: WITHOUT threads, when can a piece of code be "safely invoked"? Answer: It can be safely invoked, if it will return a correct result for any input, within the range of input for which it is defined.

See my example about memory alloc in my other mail. It shows, that a piece of code (and it's ability to be "safely invoked ") does not solely depend on the parameters passed, but also on (selected parts of) the state of the application or system.

By definition, an object is a combination of a data store and a pool of functions.

The data part can be seen as "input", for the above definition That this input is made available in a specific way does not matter.

But yes, It's your choice.

You can have an indefinite amount of definitions for each possible special case .
Or you can have one definition, using the most abstract common part of them all.

For the above it is enough to see an object as "a piece of code" (or several pieces of code), for (each of) which the data is a part of the input. It does not matter by which means this input is made available. It does not matter that the programmer does not need to explicitly specify this input.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/f8ae9c5f/attachment.html>

Reply by email

Martin
to Henry Vermaak: The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety This…
Henry Vermaak wrote 7 lines
On 10/06/11 02:09, Hans-Peter Diettrich wrote: > > What is "thread safe"? The definition is very clear here: http://en.wikipedia.org/wiki/Thread_safety

"A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the same time"

Just to point out first, I am aware of the discussion this has already sparked, and in the light of any argument of that discussion, in my opinion this definition is correct.

Yet I came to think of a case, for which I wonder, and would like to hear opinions, if indeed the above statement is complete. My query is about the part: "at the same time"

Now a piece of code could for example mix up thread local and thread global data:
- cache access to thread local data in a thread global way. Subsequent calls from another thread may fail.
- create an initialize some data, and store it thread-local, while flagging it's existence thread global. Subsequent calls from another thread may fail.
Even if such code was using some sort of locking (mutex, criticalsection, ...) it would fail. It would not need to be executed from several threads "at the same time", it fails if executed by several threads subsequently.

However so far of course each of those would also fail, if called "at the same time". So all my examples are indeed covered by the original definition.

The question is, is it prooven, or can it be prooven, that no code can be constructed, that would "not fail if called at the same time", but that would fail if called "subsequently"
That would be code, for which *during* its execution the application would be in a state valid to enter the code in another thread, but *after* it's execution, this validity would no longer be given.

If such code can be constructed, then would the above statement have to be extended to "subsequent calls of the piece of code" ?

Martin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/4b28501e/attachment.html>

Reply by email

Michael Schnell
to Martin: Unfortunately you left out the real important part of my last msg. If you choose to…

There is no question that we all agree about the technical background of all this.

The discussion I started was just about what (new) definitions makes sense to be provided in the docs to the user of an Object language to allow him to decide which object (e.g. TList vs. TThreadList) he needs to use where in his threaded application and what is allowed (e.g. accessing multiple TList instances from multiple threads with each thread only accessing one of them, or accessing any TThreadList instance from any thread) and what is forbidden (e.g accessing a single TList instance from multiple threads or accessing a TForm instance from any thread but the MainThread.)

-Michael

Reply by email

Martin
to Michael Schnell
Michael Schnell wrote 12 lines
There is no question that we all agree about the technical background of all this. The discussion I started was just about what (new) definitions makes sense to be provided in the docs to the user of an Object language to allow him to decide which object (e.g. TList vs. TThreadList) he needs to use where in his threaded application and what is allowed (e.g. accessing multiple TList instances from multiple threads with each thread only accessing one of them, or accessing any TThreadList instance from any thread) and what is forbidden (e.g accessing a single TList instance from multiple threads or accessing a TForm instance from any thread but the MainThread.)

Well, that is something, I can agree with.

*IF* a definition is supplied (with FPC/Lazarus), and in the light that the users come with all levels of experience, then it would be nice, if (in addition) an explanation would be given, rather than just a short abstract form.

In this case your wording may be misleading " just about what (new) definitions ". There would be no new definition, only an explanation, of the existing definition.

Reply by email

Mattias Gaertner
to Martin: "A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the…

?
?

Martin hat am 27. Juni 2011 um 14:47 geschrieben:

Show quoted text 22 lines
On 10/06/2011 12:26, Henry Vermaak wrote: > On 10/06/11 02:09, Hans-Peter Diettrich wrote: > > > > > What is "thread safe"? > > > The definition is very clear here: > > http://en.wikipedia.org/wiki/Thread_safety > "A piece of code is thread-safe if it can be safely invoked by multiple threads at the same time" Just to point out first, I am aware of the discussion this has already sparked, and in the light of any argument of that discussion, in my opinion this definition is correct. Yet I came to think of a case, for which I wonder, and would like to hear opinions, if indeed the above statement is complete. My query is about the part: "at the same time"

?
Think about "safely invoked" as no need for extra precautions to call it multi threaded, like e.g. critical sections or check which thread is running.? Obviously "thread-safe" does not extend the safety nor does it fix any kind of flaw that is already there when called single threaded.? And "thread safe" does not mean that calling a function multi threaded will give the same results as called single threaded. Although typically it does.? ?
And look up the definition of "function". A function is defined by the input, output and task. Failing means for some input the wrong output is returned. Input/Output are not only parameters.?
?
?

Show quoted text 7 lines
Now a piece of code could for example mix up thread local and thread global data: - cache access to thread local data in a thread global way. Subsequent calls from another thread may fail. - create an initialize some data, and store it thread-local, while flagging it's existence thread global. Subsequent calls from another thread may fail.

?
The "fail" depends on how you define the task of the function. I guess with "fail" you mean the function can fail its tasks when called multi threaded. Then it is by definition not thread safe. ?
?

Show quoted text 10 lines
Even if such code was using some sort of locking (mutex, criticalsection, ...) it would fail. It would not need to be executed from several threads "at the same time", it fails if executed by several threads subsequently. However so far of course each of those would also fail, if called "at the same time". So all my examples are indeed covered by the original definition. The question is, is it prooven, or can it be prooven, that no code can be constructed, that would "not fail if called at the same time", but that would fail if called "subsequently"

?
"At the same time" includes "subsequently", for the simple reason that critical sections are allowed, which simply turns a parallel (at the same time) into a sequential one.?
?
?

Show quoted text 6 lines
That would be code, for which *during* its execution? the application would be in a state valid to enter the code in another thread, but *after* it's execution, this validity would no longer be given. If such code can be constructed, then would the above statement have to be extended to "subsequent calls of the piece of code" ?

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/d90389fc/attachment-0001.html>

Reply by email

Andrew Brunner
to Michael Schnell: There is no question that we all agree about the technical background of all this. The…
Michael Schnell wrote
There is no question that we all agree about the technical background of all this.

Actually,

There was no mention of memory barriers other than the content in my post. So if you want to understand what that is here is a link...

http://en.wikipedia.org/wiki/Memory_barrier

Simply protecting a loop with a futex is not sufficient. Assigning variables in a multi-threaded environment is not sufficient.

Interlocked/Exchange/ExchangeAdd/Increment features must be used whenever dealing with variables (with at least one exception) In my experience arrays of boolean are atomic.

I ran tests on a HexCore AMD system which had unexplained anomalies with pointers in an bidirectional linked list. I replaced all the pointer assignments with InterlockedExchange and the system worked flawlessly. Some of the assignments were taking place in a criticalsection (btw).

Reply by email

Mattias Gaertner
to Michael Schnell: There is no question that we all agree about the technical background of all this. The…

?
?

Michael Schnell hat am 27. Juni 2011 um 14:57 geschrieben:

Show quoted text 12 lines
There is no question that we all agree about the technical background of all this. The discussion I started was just about what (new) definitions makes sense to be provided in the docs to the user of an Object language to allow him to decide which object (e.g. TList vs. TThreadList) he needs to use where in his threaded application and what is allowed (e.g. accessing multiple TList instances from multiple threads with each thread only accessing one of them, or accessing any TThreadList instance from any thread) and what is? forbidden (e.g accessing a single TList instance from multiple threads or accessing a TForm instance from any thread but the MainThread.)

The documentation can simply say about TList:
Thread safe: no
Used non thread safe global variables: none

About TAVLTree:
Thread safe: no
Used non thread safe global variables: NodeMemManager, unless overriden by SetNodeManager

No need for new terms. And everyone knows what to do to use the class in a specific thread.

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/7eda762b/attachment.html>

Reply by email

Michael Schnell
to Andrew Brunner: There was no mention of memory barriers other than the content in my post. So if you…
Andrew Brunner wrote
Simply protecting a loop with a futex is not sufficient. Assigning variables in a multi-threaded environment is not sufficient.

While I don't think we should this discuss in this context, I suggest that in the docs for the user of the object library (that was the starting point of the discussion), any type of thread-safety should include threads running on multiple processors.

Interlocked/Exchange/ExchangeAdd/Increment features must be used whenever dealing with variables (with at least one exception) In my experience arrays of boolean are atomic.

Yep. But this is only relevant if you don't protect them by a critical section, as this excludes concurrent exchange before the critical instructions are executed. Of course (when possible) using the interlocked instruction results in a lot less overhead than simply using a critical section.

I ran tests on a HexCore AMD system which had unexplained anomalies with pointers in an bidirectional linked list. I replaced all the pointer assignments with InterlockedExchange and the system worked flawlessly.

This is clear. You also would have been able to avoid the problem by using critical sections around *all *the appropriate instructions, but supposedly this would have slowed done the application greatly.

Some of the assignments were taking place in a criticalsection (btw).

I believe that the "some" were not enough.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/85c9b340/attachment.html>

Reply by email

Michael Schnell
to Mattias Gaertner: ? ? Michael Schnell hat am 27. Juni 2011 um 14:57 geschrieben: The documentation can…
Mattias Gaertner wrote 5 lines
The documentation can simply say about TList: Thread safe: no Used non thread safe global variables: none

Poor user !!!!!
If he just reads Thread safe: no, he supposedly will believe he needs to use TThreadList in all threads and do very inefficient code. How is he supposed to know that accessing a TList instance with just a single thread while accessing another instance only with another thread is safe ?

A new term (decently explained on a central location) that can be used in a Feature grid would be much more readable.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/a44ea461/attachment-0001.html>

Reply by email

Hans-Peter Diettrich
to Martin: Why? Where does the definition conflict with the above? "A piece of code is *thread-safe*…
Show quoted text 7 lines
> As stated in my former messages in this thread, IMHO, the "official" > definition of thread-safe-ness does not make much sense with objects, > but a more complex definition covering several cases of use is necessary. Why? Where does the definition conflict with the above? "A piece of code is *thread-safe* if it can be safely invoked by multiple threads at the same time"

That's the definition of reentrant subroutines only.

Show quoted text 10 lines
"Save invocation" includes that the function returns a "correct" result(output) for any "input". Where "input": - is not limited to the parameters passed in the parameter list, not even to limited to parameters passed implicitly (such as the object instance) - input includes the entire state of the system (that can be global vars, available and unavailable resources of any kind, and much more) The same applies to "result", or "output".

This would mean that a thread-safe procedure has to lock *all* input that it - or one of its called procedures - wants to read or update, before best scenario for an unrecoverable deadlock :-(

This part of "Save invocation" is not limited to thread safeness. It applies to any piece of code.

Your attempt to re-interpret above definition is of no use :-(

DoDi

Reply by email

Martin
to Mattias Gaertner: ? ? Martin hat am 27. Juni 2011 um 14:47 geschrieben: ? Think about "safely invoked" as…
Mattias Gaertner wrote 35 lines
>>> >>> What is "thread safe"? >> >> The definition is very clear here: >> >> http://en.wikipedia.org/wiki/Thread_safety > > "A piece of code is *thread-safe* if it can be safely invoked by > multiple threads at the same time" > > Just to point out first, I am aware of the discussion this has > already sparked, and in the light of any argument of that discussion, > in my opinion this definition is correct. > > Yet I came to think of a case, for which I wonder, and would like to > hear opinions, if indeed the above statement is complete. > My query is about the part: "at the same time" Think about "safely invoked" as no need for extra precautions to call it multi threaded, like e.g. critical sections or check which thread is running. Obviously "thread-safe" does not extend the safety nor does it fix any kind of flaw that is already there when called single threaded. And "thread safe" does not mean that calling a function multi threaded will give the same results as called single threaded. Although typically it does. And look up the definition of "function". A function is defined by the input, output and task. Failing means for some input the wrong output is returned. Input/Output are not only parameters.

Yes, but if I am correct, "input" for example can not (always) be limited to the list of param (not even including hidden param, like self) eg, a constructor, includes the task of allocating memory. If that fails a defined behaviour should be expected (return nil, throw exception, ...). That implies, that "available memory" in this case is part of the input.

Sure, similar flaws (with invalid data) can be constructed outside threads. But the ability to store data in either a variable local to one thread, or global to all threads does not exists without threads.

Yes the aim of the definition, is solely to extend the concept of being called safely to being called safely from several threads. But the above definition *limits* this requirement to "called at the same time"

Show quoted text 14 lines
> > Now a piece of code could for example mix up thread local and thread > global data: > - cache access to thread local data in a thread global way. > Subsequent calls from another thread may fail. > - create an initialize some data, and store it thread-local, while > flagging it's existence thread global. Subsequent calls from another > thread may fail. The "fail" depends on how you define the task of the function. I guess with "fail" you mean the function can fail its tasks when called multi threaded. Then it is by definition not thread safe.

As I said, those examples, are not actually correct (for what I am questioning) They only point into a direction.

fail = not the result that is expected according to the definition of the function (that could be: not return at all, crash, or return an incorrect value as result...)

The example is merely to indicate, that thread related problems can occur, even if calls are "not at the same time".

Yes similar issues can be constructed without threads. But without threads you do not have a differentiation between data accessible to just one thread, and data accessible to all threads. So problems arising from this, are thread related.

Show quoted text 17 lines
> Even if such code was using some sort of locking (mutex, > criticalsection, ...) it would fail. It would not need to be executed > from several threads "at the same time", it fails if executed by > several threads subsequently. > > However so far of course each of those would also fail, if called "at > the same time". So all my examples are indeed covered by the original > definition. > > The question is, is it prooven, or can it be prooven, that no code > can be constructed, that would "not fail if called at the same time", > but that would fail if called "subsequently" "At the same time" includes "subsequently", for the simple reason that critical sections are allowed, which simply turns a parallel (at the same time) into a sequential one.

There is a difference between called/invoked at the same time, and executed at the same time.

The original defintion says "invoked" they are still invoked at the same time, even though *if* a critical section is used, the part inside it (and only this part, not the whole piece of code, which includes the critical section) is executed deferred.

"at the same time" does not necessarily mean a critical section has to exist, there are other means that allow for more parallel execution: 2 read only calls, may not need to block each a
read-only call may fail due to something thread related, that happened long before (in an other thread, and only because it happened in an other thread).

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/93f52f0f/attachment.html>

Reply by email

Hans-Peter Diettrich
to Lukasz Sokol: The computer/OS/system has no clue of anything you may call 'an object'... when compiled,…
The computer/OS/system has no clue of anything you may call 'an object'... when compiled, it is just 'code'.

Right.

OOP is just a convenient abstraction, it's for people needed only :)

OOP is for designers, not for hackers ;-)

When some thread-safe code must never bring a program (automaton, system...) into an inconsistent state, objects are fine to break down the entire program into self-contained sub-systems. This allows to dramatically reduce the degree of freedom of the entire ("flattened") problem. Whatever can be done entirely inside an object, deserves no further consideration of everything outside the object.

DoDi

Reply by email

Mattias Gaertner
to Michael Schnell: Poor user !!!!! If he just reads Thread safe: no, he supposedly will believe he needs to…

?
?

Michael Schnell hat am 27. Juni 2011 um 15:54 geschrieben:

Show quoted text 6 lines
On 06/27/2011 03:34 PM, Mattias Gaertner wrote: > ? > The documentation can simply say about TList: > Thread safe: no > Used non thread safe global variables: none >

Poor user !!!!!

If he just reads Thread safe: no, he supposedly will believe he needs to use TThreadList in all threads and do very inefficient code. How is he supposed to know that accessing a TList instance with just a single thread while accessing another instance only with another thread is safe ?

?
And how is he supposed to know that this only one way of using a TList with multiple threads and that are plenty of other ways? Answer: By first reading a tutorial/book about multi threading, including critical sections etc that explains how to use thread unsafe code with multiple threads.?
Of course it would be nice if the section about thread safety has a link to such a multi threading tutorial.?
And of course you are free to provide examples for the documentation. I know, you have no time for that.?
?
?

A new term (decently explained on a central location) that can be used in a Feature grid would be much more readable.

A new term would need explanation too.

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/b85cbb14/attachment.html>

Reply by email

Andrew Brunner
to Michael Schnell: While I don't think we should this discuss in this context, I suggest that in the docs…

2011/6/27 Michael Schnell :

This is clear. You also would have been able to avoid the problem by using critical sections around all the appropriate instructions, but supposedly this would have slowed done the application greatly.

I disagree. In my experience critical sections only employ a spin-count per entrance into the block. TCriticalSection is a particialar method to ensure a code block is only accessed by one thread at a time. I strongly believe it does not ensure a "core stay" during execution. See the clearly explains the
issue of multi-core situations.

Reply by email

Mattias Gaertner
to Martin: Yes, but if I am correct, "input" for example can not (always) be limited to the list of…

?
?

Martin hat am 27. Juni 2011 um 16:01 geschrieben: [...]

Show quoted text 20 lines
> Think about "safely invoked" as no need for extra precautions to call it > multi threaded, like e.g. critical sections or check which thread is > running.? > Obviously "thread-safe" does not extend the safety nor does it fix any kind > of flaw that is already there when called single threaded.? > And "thread safe" does not mean that calling a function multi threaded will > give the same results as called single threaded. Although typically it > does.? > ? > And look up the definition of "function". A function is defined by the > input, output and task. Failing means for some input the wrong output is > returned. Input/Output are not only parameters. > Yes, but if I am correct, "input" for example can not (always) be limited to the list of param (not even including hidden param, like self) eg, a constructor, includes the task of allocating memory. If that fails a defined behaviour should be expected (return nil, throw exception, ...). That implies, that "available memory" in this case is part of the input.

In fact a function's input can even be a file on disk.? The memory manager is thread safe, so there is not much difference between single threaded and multi threaded here.?
?
?

Sure, similar flaws (with invalid data) can be constructed outside threads. But the ability to store data in either a variable local to one thread, or global to all threads does not exists without threads.

Well, this depends on pov. So this is more a philosophical question.? ?

Show quoted text 5 lines
Yes the aim of the definition, is solely to extend the concept of being called safely to being called safely from several threads. But the above definition *limits* this requirement to "called at the same time"

English lacks the exactness of mathematical expressions. ? You are right, that the definition is not exact and the wikipedia page contains a few remarks about that.
The nice thing about this definition is that everyone I knew instantly understands the idea and was able to apply it to most cases without much thinking, including methods and classes. Everyone - until I read this thread. Apparently some people have problems with it. Well, life is learning.? ?
?

Show quoted text 14 lines
> > The "fail" depends on how you define the task of the function. > I guess with "fail" you mean the function can fail its tasks when called > multi threaded. Then it is by definition not thread safe. > As I said, those examples, are not actually correct (for what I am questioning) They only point into a direction. fail = not the result that is expected according to the definition of the function (that could be: not return at all, crash, or return an incorrect value as result...)

?
Then the function is not thread safe.?
?

The example is merely to indicate, that thread related problems can occur, even if calls are "not at the same time".

True. ?
And I would like to discuss this, but I'm not sure if this topic is Lazarus related.?

?

Show quoted text 9 lines
[...] > > "At the same time" includes "subsequently", for the simple reason that > critical sections are allowed, which simply turns a parallel (at the same > time) into a sequential one. > There is a difference between called/invoked at the same time, and executed at the same time.

For "thread safe" it is the same.?
?
?

Show quoted text 13 lines
The original defintion says "invoked" they are still invoked at the same time, even though *if* a critical section is used, the part inside it (and only this part, not the whole piece of code, which includes the critical section) is executed deferred. "at the same time" does not necessarily mean a critical section has to exist, there are other means that allow for more parallel execution: ?2 read only calls, may not need to block each a read-only? call may fail due to something thread related, that happened long before (in an other thread, and only because it happened in an other thread).

Yes. But then again it is a question of how you define the task of the code. Maybe you want this behavior, maybe you don't care.? ?
?
Mattias
?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/15af3d4f/attachment.html>

Reply by email

Michael Schnell
to Andrew Brunner: 2011/6/27 Michael Schnell : I disagree. In my experience critical sections only employ a…
Andrew Brunner wrote
See the don't think Wikipedia can explain implementation details of the LCL/RTL..

But if TCriticalSection uses a MUTEX (which in fact is a FUTEX as (on Linux) it uses pthreadlib mutex function from LibC, which automatically uses FUTEX if available in the underlying arch, otherwise fallback to MUTEX) (and I believe it is implemented this way) same blocks all at the start of the section independently from the core they run on, and thus no concurrent access can happen.

-Michael

Reply by email

Andrew Brunner
to Michael Schnell

You're totally underestimating the need for a memory barrier :

"Multithreaded programming and memory visibility

See also: Memory model (computing)
Multithreaded programs usually use synchronization primitives provided by a high-level programming environment, such as Java and .NET Framework, or an application programming interface (API) such as POSIX Threads or Windows API. Primitives such as mutexes and semaphores are provided to synchronize access to resources from parallel threads of execution. These primitives are usually implemented with the memory barriers required to provide the expected memory visibility semantics. In such environments explicit use of memory barriers is not generally necessary. "

Focus on the "These primitives are usually implemented with the memory barriers required to provide the expected memory visibility semantics. "

These primitives include TCrticialSection. It's not enough to ensure that someone from another thread is reading a
it would safe to assume that CPU management systems can switch code execution on any core at any time.

Michael Schnell wrote 13 lines
On 06/27/2011 04:17 PM, Andrew Brunner wrote: > > See the link at wikipedia. I don't think Wikipedia can explain implementation details of the LCL/RTL.. But if TCriticalSection uses a MUTEX (which in fact is a FUTEX as (on Linux) it uses pthreadlib mutex function from LibC, which automatically uses FUTEX if available in the underlying arch, otherwise fallback to MUTEX) (and I believe it is implemented this way) same blocks all at the start of the section independently from the core they run on, and thus no concurrent access can happen.

Semantically Ok. Poor code performance though.. If you had 1 CriticalSection per instance of a variable you possibly could make this argument... But it's just easier and FAAASTER to use interlocked statements ;-) Locking a thread is poor practice. Just design it well and you won't have to worry about locking much. And wherever possible use interlocked features - they were designed for this issue alone.

Reply by email

Hans-Peter Diettrich
to Martin: Unfortunately you left out the real important part of my last msg. If you choose to…
See my example about memory alloc in my other mail. It shows, that a piece of code (and it's ability to be "safely invoked ") does not solely depend on the parameters passed, but also on (selected parts of) the state of the application or system.

What when some code does not return anything, *and* cannot work at all due to some problem (out-of-memory, file deleted, object destroyed...)?

When e.g. a file search cannot proceed due to missing access rights? It cannot return an boolean value (succ/fail), because it's simply unknown whether the file exists.

When in case of an unexpected error the called procedure throws an exception? Can this procedure *ever* be "safely invoked", when it may return to some other place in code (exception handler)?

DoDi

Reply by email

Martin
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 17 lines
Martin schrieb: > See my example about memory alloc in my other mail. It shows, that a > piece of code (and it's ability to be "safely invoked ") does not > solely depend on the parameters passed, but also on (selected parts > of) the state of the application or system. What when some code does not return anything, *and* cannot work at all due to some problem (out-of-memory, file deleted, object destroyed...)? When e.g. a file search cannot proceed due to missing access rights? It cannot return an boolean value (succ/fail), because it's simply unknown whether the file exists. When in case of an unexpected error the called procedure throws an exception? Can this procedure *ever* be "safely invoked", when it may return to some other place in code (exception handler)?

Yes, why not. IF this is the defined behaviour. Exceptions can be caught. To safely call such a function one would need to define an exception handler. But it can be safely called.

That a function can be safely called does not mean that there is no way to call it unsafely.

A function expecting a pointer to some specific data, may be able to check if the pointer is nil, but it can not necessarily check if the pointer is otherwise valid.
Hence input range for which the function is defined, is a pointer that is nil, or pointing to the correct type of data. Within this range of input the function may be called and will be safe, with other input the result of calling the function is not defined, hence it is not safe.

Reply by email

Michael Schnell
to Andrew Brunner: You're totally underestimating the need for a memory barrier : "Multithreaded programming…
Andrew Brunner wrote
You're totally underestimating the need for a memory barrier :

While I do know that memory barriers are the way to go to avoid the expensive use of Mutex and friends, I am positive that an MB is not necessary if all accesses to something are protected by a Mutex, as same is designed to block any thread independently from the CPU it is running on. so no other thread can even try to access that memory location. (we are not discussing how to construct a Mutex/FUTEX internally).

Focus on the "These primitives are usually implemented with the memory barriers ...

Yep, "usually" as critical sections are much more expensive.

-Michael

Reply by email

Mattias Gaertner
to Hans-Peter Diettrich: What when some code does not return anything, *and* cannot work at all due to some…

?
?

Hans-Peter Diettrich hat am 27. Juni 2011 um 16:58 geschrieben:

Show quoted text 17 lines
Martin schrieb: > See my example about memory alloc in my other mail. It shows, that a > piece of code (and it's ability to be "safely invoked ") does not solely > depend on the parameters passed, but also on (selected parts of) the > state of the application or system. What when some code does not return anything, *and* cannot work at all due to some problem (out-of-memory, file deleted, object destroyed...)? When e.g. a file search cannot proceed due to missing access rights? It cannot return an boolean value (succ/fail), because it's simply unknown whether the file exists. When in case of an unexpected error the called procedure throws an exception? Can this procedure *ever* be "safely invoked", when it may return to some other place in code (exception handler)??

Yes, if raising an IO exception is a valid output.?

?
Mattias
?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110627/b5b667ba/attachment-0001.html>

Reply by email

Lukasz Sokol
to Hans-Peter Diettrich: Right. OOP is for designers, not for hackers ;-) When some thread-safe code must never…
Hans-Peter Diettrich wrote 18 lines
Lukasz Sokol schrieb: > The computer/OS/system has no clue of anything you may call 'an > object'... when compiled, it is just 'code'. Right. > OOP is just a convenient abstraction, it's for people needed only > :) OOP is for designers, not for hackers ;-) When some thread-safe code must never bring a program (automaton, system...) into an inconsistent state, objects are fine to break down the entire program into self-contained sub-systems. This allows to dramatically reduce the degree of freedom of the entire ("flattened") problem. Whatever can be done entirely inside an object, deserves no further consideration of everything outside the object.

What I meant (and I think) it is, is that whatever thread-safe *is*, is completely orthogonal i.e. not dependent on your programming paradigm, it is completely about the resulting code. Therefore, *result* code can either be thread safe, or it can not be, there is no shades of gray here, whatever complex paradigms you apply to your language :)

(somebody correct me if I'm not correct ;)
L.

DoDi

Reply by email

Hans-Peter Diettrich
to Andrew Brunner: There was no mention of memory barriers other than the content in my post. So if you…
Show quoted text 5 lines
I ran tests on a HexCore AMD system which had unexplained anomalies with pointers in an bidirectional linked list. I replaced all the pointer assignments with InterlockedExchange and the system worked flawlessly. Some of the assignments were taking place in a criticalsection (btw).

Here I feel a need for clarification of CriticalSection in general.

Can multiple critical sections be used in a program, to protect *specific* resources? Is it wise to do so?

How can critical sections prevent concurrent access to a resource, when *not* entered as required?

Your observation suggests to me that there existed some other code, accessing the list *without* entering the (related) critical section. This would mean that *no* code can be thread-safe by itself, instead it requires *also* that all other code respects resource protection (aquire/release locks).

AFAIR TThreadList is thread-safe, because it requires to obtain (and lock) an object, before it becomes definitely
prevents all other code from accessing the protected object - provided there exist no other references to such an object outside the list. But this is no guarantee that the object itself will be protected against concurrent access to *further* resources.

My conclusion: thread-safety can be achieved only for items (procedures, objects) which do not use non-local thread-safety can be achieved only by sequentializing *all* critical operations in an process - but then we effectively are back to single-threaded code, with only a bit more of "noise" in switching the active thread in random sequence :-(

When consequently thread-safe code is entirely up to the proper use of synchronization means, what's the use of sticking an "thread-safe" attribute to anything but an entire program?

DoDi

Reply by email

Hans-Peter Diettrich
to Michael Schnell: While I do know that memory barriers are the way to go to avoid the expensive use of…
Show quoted text 5 lines
On 06/27/2011 04:58 PM, Andrew Brunner wrote: > You're totally underestimating the need for a memory barrier : While I do know that memory barriers are the way to go to avoid the expensive use of Mutex and friends, I am positive that an MB is not necessary if all accesses to something are protected by a Mutex

You forget the strength of protection. A MB will disallow immediately any concurrent access to the memory area - no way around. Protection by other means only can work in *perfect* cooperation, a very weak model.

Furthermore a MB still requires management by other means (MUTEX...), to prevent deadlocks. Unless the MB will block *any* activity on *all* the critical program data at once, what would lead to single-thread behaviour of the program.

DoDi

Reply by email

Andrew Brunner
to Hans-Peter Diettrich: You forget the strength of protection. A MB will disallow immediately any concurrent…
Hans-Peter Diettrich wrote
You forget the strength of protection. A MB will disallow immediately any concurrent access to the memory area - no way around. Protection by other means only can work in *perfect* cooperation, a very weak model.

Absolutely incorrect.

entercricitalsection();
loop
  a:=b+c;
end loop;
leavecriticalsection();

thread 2

can read a and b and c at any state. If you want an accurate view of a,b,c you need to employ interlocked statements :-)

Reply by email

Hans-Peter Diettrich
to Martin: Yes, why not. IF this is the defined behaviour. Exceptions can be caught. To safely call…
Show quoted text 7 lines
> When in case of an unexpected error the called procedure throws an > exception? Can this procedure *ever* be "safely invoked", when it may > return to some other place in code (exception handler)? Yes, why not. IF this is the defined behaviour. Exceptions can be caught. To safely call such a function one would need to define an exception handler. But it can be safely called.

This is not what I undstand as "safely called", when such a call requires protection by a try-except statement. Then the procedure with that exception handler cannot be "called safely", because the exception may lead to only *partial* processing of the try-block.

SEH is not intended for *local* protection against exceptions, this is the task of try-finally. Instead exceptions should be handled in those places, where it's possible to *repair* the possible inconsistencies, caused by an error-abort somewhere down in the call chain.

Show quoted text 6 lines
That a function can be safely called does not mean that there is no way to call it unsafely. A function expecting a pointer to some specific data, may be able to check if the pointer is nil, but it can not necessarily check if the pointer is otherwise valid.

And this is not related to "safe call" means
nothing but *reentrant*.

Hence input range for which the function is defined, is a pointer that is nil, or pointing to the correct type of data. Within this range of input the function may be called and will be safe, with other input the result of calling the function is not defined, hence it is not safe.

Then almost no procedure can be "safe", in detail in OOP with virtual methods.

DoDi

Reply by email

Hans-Peter Diettrich
to Andrew Brunner: On Mon, Jun 27, 2011 at 12:52 PM, Hans-Peter Diettrich Absolutely incorrect.…
Show quoted text 7 lines
On Mon, Jun 27, 2011 at 12:52 PM, Hans-Peter Diettrich wrote: > You forget the strength of protection. A MB will disallow immediately any > concurrent access to the memory area - no way around. Protection by other > means only can work in *perfect* cooperation, a very weak model. Absolutely incorrect.

Why?

entercricitalsection();

Where do you see a memory barriere here?

DoDi

Reply by email

Marco van de Voort
to Hans-Peter Diettrich: Right. OOP is for designers, not for hackers ;-) When some thread-safe code must never…
Hans-Peter Diettrich wrote 10 lines
> OOP is just a convenient abstraction, it's for people needed only :) OOP is for designers, not for hackers ;-) When some thread-safe code must never bring a program (automaton, system...) into an inconsistent state, objects are fine to break down the entire program into self-contained sub-systems. This allows to dramatically reduce the degree of freedom of the entire ("flattened") problem. Whatever can be done entirely inside an object, deserves no further consideration of everything outside the object.

Are you talking about monitors? How else will you force an object with only one thread in it?

Or are you meaning thread+TLS+state exclusively used in the thread as object?

I've been following this subthread for a couple of posts yet, and the whole picture leaves an vague feeling.

Reply by email

Andrew Brunner
to Hans-Peter Diettrich: Why? Where do you see a memory barriere here? DoDi
Hans-Peter Diettrich wrote
> Absolutely incorrect. Why?

Two reasons.

1.) Visibility. A critical section does not particularly protect visibility as with 2 threads accessing a piece of memory.

2.) Execution Order. A critical section does not protect or ensure that code will be executed in any particular order. This is where multi-core/multi-threaded systems vs theory get extremely complicated. AMD vs Intel. Kernels Linux vs Windows. The only way to make sure you can get code in proper order with regard to memory assignments ( specifically variables) is to use Interlocked methods. This is why they were designed.

The analogy would be like using a wisk vs a commerical grade mixer to scramble your eggs. Use the commercial grade mixer in this case (CriticalSection) and expect a high cost of use and tons of wait states - which translates into poor benchmarks.

Reply by email

Malcom Haak
to Andrew Brunner

However there are MANY cases where execution order does not matter. These are the BEST cases for threads.
In most of these cases there is a long list of work to be done, none of which references any of the other work. Some examples include brute force solving of complex hashing functions,
downloading of large lists of files or basically any time you have lots of 'slow' work that you know all the details about in advance. In these cases all you have are self-contained threads that need to pull from one list and possibly push answers to another.

Tell me then why any of what you have said is relevant. In fact in cases this this the use of CriticalSections would be sensible and would not cause 'tons of wait' as you have all your worker threads off doing things 99% of the time.

Also If you have lots of code that requires things to happen in specific orders, I think you need to re-evaluate your use of threads. Attempts to make things that require synchronous processing or order, suddenly asynchronous is just stupid and fraught with issues. Most of the time you should find a 'string of tasks' that can be done asynchronously, this is what you get threads to do. IF all the processing you have requires specific execution order then don't use threads.. The other possibility is that you are just doing it wrong.

I don't see how the idea of Execution order is that hard, it should be seen like giving tasks to 100's of people when organising a large event or something. I think most of the 'difficulty' for programmers with multi-threading is understanding how to delegate.

Andrew Brunner wrote 31 lines
On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich wrote: >> Absolutely incorrect. > > Why? > Two reasons. 1.) Visibility. A critical section does not particularly protect visibility as with 2 threads accessing a piece of memory. 2.) Execution Order. A critical section does not protect or ensure that code will be executed in any particular order. This is where multi-core/multi-threaded systems vs theory get extremely complicated. AMD vs Intel. Kernels Linux vs Windows. The only way to make sure you can get code in proper order with regard to memory assignments ( specifically variables) is to use Interlocked methods. This is why they were designed. The analogy would be like using a wisk vs a commerical grade mixer to scramble your eggs. Use the commercial grade mixer in this case (CriticalSection) and expect a high cost of use and tons of wait states - which translates into poor benchmarks. -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110628/3f960000/attachment.html>

Reply by email

Andrew Brunner
to Malcom Haak

2011/6/27 Malcom Haak :

Tell me then why any of what you have said is?relevant. In fact in cases this this the use of CriticalSections would be sensible and would not cause 'tons of wait' as you have all your worker threads off doing things 99% of the time.

Thread 1:
a=b+c
a2=a+c2
SignalEvent(E1)

Thread 2:

  repeat
  WaitForEvent(E1,120);
    We can read anything now
  until terminated or complete

This the prime example. On a 6 core system a looks like one value to one core than it does to another core. It's that simple. No getting around this issue.

While spinlocks can block a entrance - it cannot guarantee memory order / code execution order. Therefore it is good practice to adopt interlocked assignments to guarantee memory is what it is.

Core X computes a=b+c
Core X+Y computes a2

This is relatively new theory which required low-level CPU code to perform such locks. This was never needed until the introduction of multi-core systems. Of which I did extensive tests on AMD via FPC/Lazarus.

Reply by email

Reimar Grabowski
to Andrew Brunner
This is relatively new theory which required low-level CPU code to perform such locks. This was never needed until the introduction of multi-core systems.

Excuse my ignorance but what is different on multi-core systems compared to multi-processor systems which are around for quite some time?

R.

Reply by email

Malcom Haak
to Andrew Brunner: 2011/6/27 Malcom Haak : Thread 1: a=b+c a2=a+c2 SignalEvent(E1) Thread 2: repeat…
Andrew Brunner wrote 9 lines
2011/6/27 Malcom Haak : > Tell me then why any of what you have said is relevant. In fact in cases > this this the use of CriticalSections would be sensible and would not cause > 'tons of wait' as you have all your worker threads off doing things 99% of > the time. Firstly, I was referring to my example
Show quoted text 6 lines
Thread 1: a=b+c a2=a+c2 SignalEvent(E1) This will run in 1 thread.. if you use local variables this is fine. if you

were using global variables you are an idiot.

Show quoted text 6 lines
Thread 2: repeat WaitForEvent(E1,120); We can read anything now until terminated or complete

This the prime example. On a 6 core system a looks like one value to

one core than it does to another core. It's that simple. No getting around this issue. OF WHAT? bad code? It would only look different if you are looking at

different parts of memory.. or you hadn't finished writing.

Show quoted text 5 lines
While spinlocks can block a entrance - it cannot guarantee memory order / code execution order. Therefore it is good practice to adopt interlocked assignments to guarantee memory is what it is. Also what the hell are you on about? You could use CriticalSections in your

example and it would work fine. The fact you have one Thread doing nothing for ever is a tad silly and to me shows you have no idea what you are doing.. but that could be just because of the exceedingly limited scope of the example.

Show quoted text 5 lines
Core X computes a=b+c Core X+Y computes a2 Why would you spilt this into different threads??

If it is the same thread it does not matter if it moves CPU... Your example is lacking in sanity.

Show quoted text 6 lines
This is relatively new theory which required low-level CPU code to perform such locks. This was never needed until the introduction of multi-core systems. Of which I did extensive tests on AMD via FPC/Lazarus. Yeah your just sounding silly here. As per Reimar Grabowski's comment,

whats the difference between multi-core and Multi-processor? I'll tell you... accessibility to people who don't know what they are on about.

Show quoted text 6 lines
-- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110628/2d38cfa2/attachment.html>

Reply by email

Mattias Gaertner
to Reimar Grabowski: On Mon, 27 Jun 2011 18:41:46 -0500 Excuse my ignorance but what is different on…
Show quoted text 8 lines
On Mon, 27 Jun 2011 18:41:46 -0500 Andrew Brunner wrote: > This is relatively new theory which required low-level CPU code to > perform such locks. This was never needed until the introduction of > multi-core systems. Excuse my ignorance but what is different on multi-core systems compared to multi-processor systems which are around for quite some time?

They used a more conservative cache system. A write automatically invalidated the cache of the other cpus.

Mattias

Reply by email

Michael Schnell
to Hans-Peter Diettrich: You forget the strength of protection. A MB will disallow immediately any concurrent…
Hans-Peter Diettrich wrote
You forget the strength of protection.

Maybe I seem to see what you mean.

You think, a critical section will not prevent that the data that is accessed by both threads is duplicated in a register or in the Data cache of the two (or more) CPUs that are trying to access the resource (variable). Thus a concurrent access might erroneously offer a not updated state to the other CPU.

But

Regarding Registers, the C language provides the "volatile" keyword to prevent the code from caching the values of such variables in registers. With Pascal (that does not have the volatile keyword), all static data is handled as volatile. This might in fact trigger a protection problem, as (AFAIK) data on the heap (e.g. class variables) are not handled as volatile. But this potential problem with threads accessing class variables or e.g. a linked list is independent from SMP. In fact I have no idea if/how this can be handled with Pascal-language means.

Regarding Data Cache, AFAIK, the hardware prevents this. If one CPU writes a value, an "invalidate" signal for the addresses in that cache line is sent to all caches, and so all other CPUs will reread the data from the main memory, which in turn will force a preliminary write from cache to main memory for the cache line of the first CPU.

If this would not be true, practically no threaded application would work, as a thread would close to never see what another thread writes, as with today's huge cache sizes normally any data written by a thread resides completely in the "personal" cache of the CPU it runs on.

Thus "Locked" instructions (that force this mechanism, guaranteeing proper read-modify-write access even if multiple instructions access the same data are issued at the same time <overlapping execution> ) only are necessary outside a critical section protecting the data in question. (And this in fact is necessary to create the MUTEX/FUTEX functionality itself, and to do code the performance/latency of which would suffer too much from introducing critical sections.)

If you think I get this wrong, please do provide an example how you think such a conflict within a critical section might happen.

My conclusion is, that the said problem with linked lists results from the pointers not being defined as "volatile". And I really don't know how this could be cured in Pascal other than doing ASM. (I was not aware of this problem and I feel it should be discussed in the FPC mailing list.)

-Michael

Reply by email

Michael Schnell
to Andrew Brunner: On Mon, Jun 27, 2011 at 12:52 PM, Hans-Peter Diettrich Absolutely incorrect.…
Andrew Brunner wrote 11 lines
entercricitalsection(); loop a:=b+c; end loop; leavecriticalsection(); thread 2 can read a and b and c at any state. If you want an accurate view of a,b,c you need to employ interlocked statements :-)

Hmm.
In this example, b and c are not modified so in fact any view is accurate at a certain point of time. Moreover doing the critical section outside of a lop does not make much sense.

A more obvious example would be

Thread 1:

loop
   entercricitalsection();
   a:=a+1;
   b:=b+a;
   leavecriticalsection();
end loop;

Here another thread just fetching a and b could get inconsistent (not representing a the same loop) value of a and b.

IMHO if the other thread would do

   entercricitalsection();
   a1:=a;
   a2:=b+a;
   leavecriticalsection();
   write a1 and a2

it will show consistant values.

Here, it is not possible to force consistent values by interlocked
instructions, as there is no interlocked instruction that does a:=a+1
and b:=b+a in a single hardware lock. So using the critical section in
both threads is necessary to force consistency.

An example that can be done with interlocked instructions (and thus prevents the huge overhead introduced by a critical section) is

Thread 1:

loop
   a:=a+1;
end loop;

Thread 2:

loop
   a:=a-1;
end loop;

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110628/56970b58/attachment.html>

Reply by email

Michael Schnell
to Andrew Brunner: On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich Two reasons. 1.) Visibility. A…
Andrew Brunner wrote
2.) Execution Order.

As a critical section is a function call, it prevents instructions are re-ordered from being inside of the protected code sequence to being outside. And what happens inside the protected code sequence is not prone to mutual access anyway.

Please do not odder any analogies but construct a decent example sowing how you think something can go wrong and why.

-Michael

Reply by email

Michael Schnell
to Andrew Brunner: 2011/6/27 Malcom Haak : Thread 1: a=b+c a2=a+c2 SignalEvent(E1) Thread 2: repeat…
Andrew Brunner wrote 9 lines
2011/6/27 Malcom Haak: > In fact in cases > this this the use of CriticalSections would be sensible and Thread 1: ... This is relatively new theory which required low-level CPU code to perform such locks. This was never needed until the introduction of multi-core systems. Of which I did extensive tests on AMD via FPC/Lazarus.

We are discussing here if a critical would offer data integrity with threads or not (without additionally using low level CPU code). Your example does not say anything about this.

Of course we all know that in certain cases there are better performing option than critical sections (using low level code). But this is not to be discussed right now.

-Michael

Reply by email

Michael Schnell
to Michael Schnell: Hmm. In this example, b and c are not modified so in fact any view is accurate at a…
Michael Schnell wrote
...

I forgot to mention that the variables a and b need to be defined as volatile (mentioning this C-keyword) and thus need to be global/static which makes Pascal to handle them as volatile (not cashing them in CPU registers). I don't know if/how it in Pascal is possible to define stack-variables to be handled as volatile.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110628/db9fc08f/attachment.html>

Reply by email

Henry Vermaak
to Andrew Brunner: On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich Two reasons. 1.) Visibility. A…
Andrew Brunner wrote
2.) Execution Order. A critical section does not protect or ensure that code will be executed in any particular order. This is where

How do you know this? Unfortunately I can't read the code for the Windows critical sections and the documentation doesn't explicitly state anything, but at least pthread mutex guarantees a memory barrier. So if you're using the fpc rtl critical sections on unix (which uses pthread_mutex), your statement is false.

You'll have to read the generated assembler for Windows critical sections. My hunch would be that they use memory barriers, too.

Henry

Reply by email

Michael Schnell
to Andrew Brunner: On Mon, Jun 27, 2011 at 1:05 PM, Hans-Peter Diettrich That all changed with the…
Andrew Brunner wrote 5 lines
That all changed with the introduction of multi-core systems. But in those days everything was inline. Now a days everything is running in parallel.

Yep. But the user application code just sees threads.

Since ages, the user code needs to consider threads to work concurrently and any instruction of each active thread can be executed at exactly the same time, exactly as if each thread has it's own CPU. So any possible concurrent access needs to be protected by the means that are offered by the appropriate libraries (e.g. critical section).

Thus regarding the user code there is no dirty
details need to be handled by the infrastructure (compiler, libraries, OS).

If the user code needs more performance that this simple paradigm can offer it might introduce low level stuff (such as interlocked instructions). But I would not consider such programs "user code" any more.

-Michael

Reply by email

Henry Vermaak
to Andrew Brunner: On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich Two reasons. 1.) Visibility. A…
Andrew Brunner wrote
AMD vs Intel. Kernels Linux vs Windows. The only way to make sure

How does the kernel matter?

Other than the cpu, compilers can also reorder instructions. You can use __asm__ __volatile__("": : :"memory") in c to stop gcc from screwing around with the order, for example. This is of course if a hardware memory barrier isn't necessary.

you can get code in proper order with regard to memory assignments ( specifically variables) is to use Interlocked methods. This is why they were designed.

No. You have to use memory barriers for this. Atomic operations are only useful for single data elements.

Read Paul McKenney's excellent book:

http://kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html

Henry

Reply by email

Henry Vermaak
to Henry Vermaak: How do you know this? Unfortunately I can't read the code for the Windows critical…
Henry Vermaak wrote 13 lines
On 27/06/11 23:31, Andrew Brunner wrote: > > 2.) Execution Order. A critical section does not protect or ensure > that code will be executed in any particular order. This is where How do you know this? Unfortunately I can't read the code for the Windows critical sections and the documentation doesn't explicitly state anything, but at least pthread mutex guarantees a memory barrier. So if you're using the fpc rtl critical sections on unix (which uses pthread_mutex), your statement is false. You'll have to read the generated assembler for Windows critical sections. My hunch would be that they use memory barriers, too.

http://msdn.microsoft.com/en-us/library/ms686355%28v=VS.85%29.aspx confirms this.

Henry

Reply by email

Henry Vermaak
to Henry Vermaak: How does the kernel matter? Other than the cpu, compilers can also reorder instructions. …
Henry Vermaak wrote 16 lines
On 27/06/11 23:31, Andrew Brunner wrote: > AMD vs Intel. Kernels Linux vs Windows. The only way to make sure How does the kernel matter? Other than the cpu, compilers can also reorder instructions. You can use __asm__ __volatile__("": : :"memory") in c to stop gcc from screwing around with the order, for example. This is of course if a hardware memory barrier isn't necessary. > you can get code in proper order with regard to memory assignments ( > specifically variables) is to use Interlocked methods. This is why > they were designed. No. You have to use memory barriers for this. Atomic operations are only useful for single data elements.

To add to this, on x86 the memory barrier is probably implemented with an atomic instruction.

Henry

Reply by email

Hans-Peter Diettrich
to Marco van de Voort: Are you talking about monitors? How else will you force an object with only one thread in…
Show quoted text 16 lines
On Mon, Jun 27, 2011 at 03:05:36PM +0100, Hans-Peter Diettrich wrote: >> OOP is just a convenient abstraction, it's for people needed only :) > OOP is for designers, not for hackers ;-) > > When some thread-safe code must never bring a program (automaton, > system...) into an inconsistent state, objects are fine to break down > the entire program into self-contained sub-systems. This allows to > dramatically reduce the degree of freedom of the entire ("flattened") > problem. Whatever can be done entirely inside an object, deserves no > further consideration of everything outside the object. Are you talking about monitors? How else will you force an object with only one thread in it? Or are you meaning thread+TLS+state exclusively used in the thread as object?

I'm not talking specifically about threads here, instead of OOP and program design in general. An interactive program is much harder to control than a batch-style program with almost sequential control flow. When you try to create a state/transition diagram (automaton, state machine), with allowed actions and transitions for every possible state, then this will be almost impossible for an interactive program (too many possible states). When that huge automaton is broken down into sub-automatons (objects), with their own internal states and transitions, then the overall application will have to respect only a fraction of the total possible states. Every object will settle down in a limited set of allowed states, and the logic of the main program must not deal with the many *intermediate* states, that may occur inside an object.

Imagine a file object, that may implement included files, an undo list and whatever you like. Such an object includes many sub-objects (lists...) and variables (file positions, undo pointers...), which can be in very many different states (values). But those states, that are of interest to the controlling program, can be restricted to simple informations like IsOpen:boolean, and all further validity checks and transitions can be encapsulated in the publicly accessible methods (actions).

This model can be extended for threads, where a single test for e.g. obj.Locked will reveal whether access to *all* of the object's members is currently allowed. When such objects know about related objects, that will be accessed during some operation (method call), the number of these objects will be much lower than the number of variables, that had to be locked *individually* before the operation can start. That reduced number of dependencies will simplify the implementation of strategies for deadlock prevention and resolution.

I've been following this subthread for a couple of posts yet, and the whole picture leaves an vague feeling.

ACK. Using threads requires more than only TThread objects, which are useless without a reliable thread synchronization model, *and* an according implementation of this model in application specific code.

DoDi

Reply by email

Michael Schnell
to Henry Vermaak: To add to this, on x86 the memory barrier is probably implemented with an atomic…
Henry Vermaak wrote
To add to this, on x86 the memory barrier is probably implemented with an atomic instruction.

Like MUTEX/FUTEX (and critical section) on the system level all this needs to be done using atomic (and with SMP bus locking / cache invalidating) instructions (with no-SMP, disabling the interrupt would be another system-level option).

-Michael

Reply by email

Hans-Peter Diettrich
to Andrew Brunner: On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich Two reasons. 1.) Visibility. A…
Show quoted text 10 lines
On Mon, Jun 27, 2011 at 2:51 PM, Hans-Peter Diettrich wrote: >> Absolutely incorrect. > Why? > Two reasons. 1.) Visibility. A critical section does not particularly protect visibility as with 2 threads accessing a piece of memory.

This is exactly what I wanted to say. A critical section does *not* enforce a MB (by visibility).

2.) Execution Order. A critical section does not protect or ensure that code will be executed in any particular order.

Right. When execution order (race conditions) is of interest, it must be established by other means. Here is where deadlocks enter the scene.

I think that you didn't understand what I wanted to say. Hard to tell, due to the snipped details you are referring to :-(

DoDi

Reply by email

Hans-Peter Diettrich
to Andrew Brunner: 2011/6/27 Malcom Haak : Thread 1: a=b+c a2=a+c2 SignalEvent(E1) Thread 2: repeat…
This is relatively new theory which required low-level CPU code to perform such locks.

This is not new. String operations (CMPS...) can be interrupted since a long time, and it took some more time until even the single-core CPUs could resume such an interrupted instruction correctly.

You're right that CMPXCHG and similar instructions have been missing in older instruction sets, but these would have been useful also in single-core CPUs with interrupt capabilities. Really new is the need for cache synchronization, when multiple processors or cores use their own caches, including on-chip (instruction...) caches. But wasn't this already of concern in memory-mapped I/O (graphics cards)? Cache "look aside"?

DoDi

Reply by email

Mark Morgan Lloyd
to Henry Vermaak: How do you know this? Unfortunately I can't read the code for the Windows critical…
Henry Vermaak wrote 13 lines
On 27/06/11 23:31, Andrew Brunner wrote: > > 2.) Execution Order. A critical section does not protect or ensure > that code will be executed in any particular order. This is where How do you know this? Unfortunately I can't read the code for the Windows critical sections and the documentation doesn't explicitly state anything, but at least pthread mutex guarantees a memory barrier. So if you're using the fpc rtl critical sections on unix (which uses pthread_mutex), your statement is false. You'll have to read the generated assembler for Windows critical sections. My hunch would be that they use memory barriers, too.

On processors that support them, which I think excludes x86.

My understanding is that in the general case membars are there to enforce sanity when a processor can reorder memory accesses. As such they don't guarantee anything either way when multiple threads are considered on an SMP/multicore system, they're just part of the overall picture.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Michael Schnell
to Hans-Peter Diettrich: This is exactly what I wanted to say. A critical section does *not* enforce a MB (by…
Hans-Peter Diettrich wrote
This is exactly what I wanted to say. A critical section does *not* enforce a MB (by visibility).

All references I read today say that pthread_mutex (on which supposedly TCriticalSection is based) and the appropriate Windows stuff does contain an MB. But there might be issues with other OSes and Archs.

If they would not do so, the complete plain old threaded application paradigm would be invalid, and tons of applications would need to be trashed.

-Michael

Reply by email

Andrew Brunner
to Malcom Haak: On Tue, Jun 28, 2011 at 9:41 AM, Andrew Brunner were using global variables you are an…

2011/6/27 Malcom Haak :

OF WHAT? bad code? It would only look different if you are looking at different parts of memory.. or you hadn't finished writing.

Are you serious?

Show quoted text 5 lines
Also what the hell are you on about? You could use CriticalSections in your example and it would work fine. The fact you have one Thread doing nothing for ever is a tad silly and to me shows you have no idea what you are doing.. but that could be just because of the exceedingly limited scope of the example.

You haven't a clue.

Show quoted text 7 lines
> > Core X computes a=b+c > Core X+Y computes a2 > Why would you spilt this into different threads?? If it is the same thread it does not matter if it moves CPU... Your example is lacking in sanity.

This code is written and compiled to execute in thread 1 as per example.

Line T : Core X computes a=b+c
Line T+1 : Core X+Y computes a2

T+1 most likely will be completed before line T is computed!

And it is not poor practice to have threads communicating reading/writing variables. Your lack of understanding multi-threaded systems is evident.

Show quoted text 9 lines
> This is relatively new theory which required low-level CPU code to > perform such locks. ?This was never needed until the introduction of > multi-core systems. ?Of which I did extensive tests on AMD via > FPC/Lazarus. > Yeah your just sounding silly here. As per Reimar Grabowski's comment, whats the difference between multi-core and Multi-processor? I'll tell you...?accessibility to people who don't know what they are on about.

No. I speak with experience. Whether or not you are able to learn/comprehend what I am illustrating - that is a different matter.

Reply by email

Andrew Brunner
to Michael Schnell: All references I read today say that pthread_mutex (on which supposedly TCriticalSection…
Michael Schnell wrote
All references I read today say that pthread_mutex (on which supposedly TCriticalSection is based) and the appropriate Windows stuff does contain an MB. But there might be issues with other OSes and Archs.

Yes, any object that requires atomic features will employ a memory barrier. That is to say the MB is employed in order for the spincount to be accurate across all cores.

Show quoted text 5 lines
If they would not do so, the complete plain old threaded application paradigm would be invalid, and tons of applications would need to be trashed. -Michael

Probably right here. My engine had worked fine on a tripple core AMD. It wasn't until I upgraded to the 6 core system did I have to start looking into what was causing random problems with pointer assignments.

Reply by email

Michael Schnell
to Hans-Peter Diettrich: I'm not talking specifically about threads here, instead of OOP and program design in…
Hans-Peter Diettrich wrote
*and* an according implementation of this model in application specific code.

Yep but the application program should not (need to) be aware of what architecture (Processor-Type, SMP,...) it is running on nor know about the underlying OS or system libraries (MUETX/FUTEX, ...). For the user program, protecting the data structures by TCriticalSection() (if necessary according to the description e.g. of the LCL objects it uses) should suffice.

If this is not like that, I consider it a bug. Which might not be helpful if there is no decent way to cure it. In this case: what workaround can be used ?

-Michael

Reply by email

Henry Vermaak
to Michael Schnell: Like MUTEX/FUTEX (and critical section) on the system level all this needs to be done…
Michael Schnell wrote 10 lines
On 06/28/2011 12:24 PM, Henry Vermaak wrote: > > To add to this, on x86 the memory barrier is probably implemented with > an atomic instruction. > Like MUTEX/FUTEX (and critical section) on the system level all this needs to be done using atomic (and with SMP bus locking / cache invalidating) instructions (with no-SMP, disabling the interrupt would be another system-level option).

Different architectures have specific memory barrier instructions which must be used. For example, arm has DMB, DSB, ISB.

Henry

Reply by email

Andrew Brunner
to Michael Schnell: As for a user program the only way to handle atomic operations is to protect them by a…
Michael Schnell wrote 6 lines
As said before besides all this complicated stuff the critical variable needs to be handled as volatile by the compiler (not caching it in a register while opening or closing the critical section). I have no Idea how this can be enforced in FPC.

You are wrong. There is no complicated stuff. Just use interlocked assignments for high performance computing :-)

Reply by email

Michael Schnell
to Andrew Brunner: Yes, any object that requires atomic features will employ a memory barrier. That is to…
Andrew Brunner wrote
Yes, any object that requires atomic features will employ a memory barrier. That is to say the MB is employed in order for the spincount to be accurate across all cores.

As for a user program the only way to handle atomic operations is to protect them by a MUTEX (TCriticalSection in FPC) and same does include the memory barrier we hopefully are safe.

My engine had worked fine on a tripple core AMD. It wasn't until I upgraded to the 6 core system did I have to start looking into what was causing random problems with pointer assignments.

Of course it might be possible that it just was good luck that it worked on the 3-Core (because the bad timing condition did not ever occur). But there also might be some bug somewhere.

As said before besides all this complicated stuff the critical variable needs to be handled as volatile by the compiler (not caching it in a register while opening or closing the critical section). I have no Idea how this can be enforced in FPC.

-Michael

Reply by email

Michael Schnell
to Andrew Brunner: You are wrong. There is no complicated stuff. Just use interlocked assignments for high…
Andrew Brunner wrote
There is no complicated stuff. Just use interlocked assignments for high performance computing :-)

This is low level stuff and not what "user programs" are supposed to do. User land programs only know Posix as their system interface.

If the performance of Posix is not good enough you can use low level interfaces to do very dedicated non portable high performance programs.

But when only using Posix the program should work correctly on all systems that provide Posix (including a million core SMP). Otherwise somewhere there is a bug.

-Michael

Reply by email

Andrew Brunner
to Michael Schnell
Michael Schnell wrote 7 lines
On 06/28/2011 03:00 PM, Andrew Brunner wrote: > > There is no complicated stuff. Just use interlocked > assignments for high performance computing :-) This is low level stuff and not what "user programs" are supposed to do. User land programs only know Posix as their system interface.

LOL All the Interlocked / Compare and Swap statements are included in the system unit and are readily available and tested (at least on AMD).

Reply by email

Michael Schnell
to Andrew Brunner
Andrew Brunner wrote
LOL All the Interlocked / Compare and Swap statements are included in the system unit and are readily available and tested (at least on AMD).

I don't know an IDE called "AMD" ;-) .

I already did some research and found that on ARM there seem to be issues with those.

On X64 there are hardware instructions for these operations, so I believe they will work as expected (atomic but not memory ordering).

But if you need to do atomic operations that are moire complex than what a single x86 instruction provides, you still need to use MUTEX (CriticalSection). And same is bound to work on all systems (including SMP) according to the Posix specs.

-Michael

Reply by email

Henry Vermaak
to Hans-Peter Diettrich: When a critical section object is owned, the only other threads affected are the threads…
Hans-Peter Diettrich wrote 14 lines
Henry Vermaak schrieb: > You'll have to read the generated assembler for Windows critical > sections. My hunch would be that they use memory barriers, too. >> When a critical section object is owned, the only other threads affected are the threads that are waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue running. << I don't see anything like memory barriers here.

Quoting from
http://msdn.microsoft.com/en-us/library/ms686355%28v=VS.85%29.aspx

The following synchronization functions use the appropriate barriers to ensure memory ordering:

Functions that enter or leave critical sections
Functions that signal synchronization objects
Wait functions
Interlocked functions

Henry

Reply by email

Hans-Peter Diettrich
to Henry Vermaak: How do you know this? Unfortunately I can't read the code for the Windows critical…
You'll have to read the generated assembler for Windows critical sections. My hunch would be that they use memory barriers, too. >

When a critical section object is owned, the only other threads affected are the threads that are waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue running.
<<

I don't see anything like memory barriers here.

DoDi

Reply by email

Michael Schnell
to Hans-Peter Diettrich: Big Q: *which* resource? A critical section (process-local MUTEX) is not related to a…
Hans-Peter Diettrich wrote 8 lines
A critical section (process-local MUTEX) is not related to a specific (memory) resource, except itself, consequently it can not protect any *other* resource. It also does not block any other thread, not waiting for entering the critical section, so that all resources are accessible by all threads, except the critical section (or mutex...) itself.

I understand that you are supposed to do

  CriticalSection.Enter;
    do something with the variables that are protected
  CriticalSection.leave;

What did you think how to use them ? Of course a MUTEX can do other things, too, but here we are discussing "normal" CriticalSection use. -Michael

Reply by email

Andrew Brunner
to Hans-Peter Diettrich: Big Q: *which* resource? A critical section (process-local MUTEX) is not related to a…
Hans-Peter Diettrich wrote 7 lines
Big Q: *which* resource? A critical section (process-local MUTEX) is not related to a specific (memory) resource, except itself, consequently it can not protect any *other* resource. It also does not block any other thread, not waiting for entering the critical section, so that all resources are accessible by all threads, except the critical section (or mutex...) itself.

100% correct. That's what I've been saying. I think some think that its some magical solution that protects everything under the sun.

Show quoted text 5 lines
> Thus a concurrent access might erroneously offer a not updated state to > the other CPU. Right. All threads keep running, except those waiting for a critical section in use, so that concurrent access can occur in all threads.

Simple semantics.

Show quoted text 8 lines
> Regarding Data Cache, AFAIK, the hardware prevents this. If one CPU writes > a value, an "invalidate" signal for the addresses in that cache line is sent > to all caches, and so all other CPUs will reread the data from the main > memory, which in turn will force a preliminary write from cache to main > memory for the cache line of the first CPU. An invalidated cache line does not cause a reload from RAM. A reload only occurs when the next read will result in an cache miss.

OK folks. Can we please focus around this comment ??? This is what makes a piece of memory volatile with respect to threading/cores. CAS / Interlocked mechanisms are the solution to this issue. But are there others?

Show quoted text 7 lines
> Thus "Locked" instructions (that force this mechanism, guaranteeing proper > read-modify-write access even if multiple instructions access the same data > are issued at the same time <overlapping execution> ) only are necessary > outside a critical section protecting the data in question. That's wrong, since a critical section does not protect any range of memory addresses.

Ok another focus here. Lets make the distinction between Thread Locks and Interlocked/Compare and Swaps here. Anyone else got anything to add here?

Show quoted text 5 lines
A locking instruction most probably will invalidate the address in all caches, before reading from or writing to the specified address. Since the RAM is locked during the instruction, all other cores or processors have to wait until the end of the instruction cycle, before they can access the same address.

This is good info. This is exactly what I observed on my AMD 1075Ts

Show quoted text 13 lines
> My conclusion is, that the said problem with linked lists results from the > pointers not being defined as "volatile". No. In a bidirectionally linked list up to 4 pointers have to be updated together, whenever an element is inserted or removed. This leaves much room for race conditions, that cannot be cured by protecting every single pointer. Instead the entire chain must be protected, by a MUTEX or other synchronization means. And then it's only a *convention*, which object or memory block shall be protected by a MUTEX, no memory barrier prevents access without obtaining the MUTEX first. Kind of a memory barrier can be established by putting the list object (head) into a TThreadList, *provided that* no code will retain references to list elements after releasing the list object.

I had a similar issue once. And it was solved with bringing the list under my manager/worker system so that there was only one thread accessing the linkedlist, and I used InterlockedExchange for First,Last,Next,Previous.

Show quoted text 7 lines
> And I really don't know how this could be cured in Pascal other than doing > ASM. (I was not aware of this problem and I feel it should be discussed in > the FPC mailing list.) It's not a matter of the language, when a thread does *not* aquire a lock before accessing the related resource. It's simply a design flaw, when some piece of code does not obey the established rules.

I don't see how this is an issue of obedience. It's more of a phenomenon.

Reply by email

Michael Schnell
to Hans-Peter Diettrich: Big Q: *which* resource? A critical section (process-local MUTEX) is not related to a…
Hans-Peter Diettrich wrote 11 lines
No. In a bidirectionally linked list up to 4 pointers have to be updated together, whenever an element is inserted or removed. This leaves much room for race conditions, that cannot be cured by protecting every single pointer. Instead the entire chain must be protected, by a MUTEX or other synchronization means. And then it's only a *convention*, which object or memory block shall be protected by a MUTEX, no memory barrier prevents access without obtaining the MUTEX first. Kind of a memory barrier can be established by putting the list object (head) into a TThreadList, *provided that* no code will retain references to list elements after releasing the list object.

I fully agree. With the RTL/LCL, the MUTEX is encapsulated in the TCtriticalSection Object (one MUTEX per instance. And of course, here, a single instance is necessary to be used for all accesses to the pointers). And as the Mutex already contains the Full Fence memory barrier and (as discussed over in the fpc list) the function calls to Enter and Leave prevents the compiler from caching any of the intermediate pointer values in registers at a wrong point in time, I don't see why CriticalSection would not be the correct way to go and work as expected. (OTOH using atomic interlocked ASM instructions does not help as all pointers need to be updated in a single atomic operation).

But the original claim was that the implementation with Critical sections failed on a multi core engine and interlocked instructions helped.

This is why I suggested that there is some kind of bug.

-Michael

Reply by email

Hans-Peter Diettrich
to Michael Schnell: Maybe I seem to see what you mean. You think, a critical section will not prevent that…
Show quoted text 9 lines
On 06/27/2011 07:52 PM, Hans-Peter Diettrich wrote: > > You forget the strength of protection. Maybe I seem to see what you mean. You think, a critical section will not prevent that the data that is accessed by both threads is duplicated in a register or in the Data cache of the two (or more) CPUs that are trying to access the resource (variable).

Big Q: *which* resource?

A critical section (process-local MUTEX) is not related to a specific (memory) resource, except itself, consequently it can not protect any *other* resource. It also does not block any other thread, not waiting for entering the critical section, so that all resources are accessible by all threads, except the critical section (or mutex...) itself.

Thus a concurrent access might erroneously offer a not updated state to the other CPU.

Right. All threads keep running, except those waiting for a critical section in use, so that concurrent access can occur in all threads.

Show quoted text 5 lines
Regarding Data Cache, AFAIK, the hardware prevents this. If one CPU writes a value, an "invalidate" signal for the addresses in that cache line is sent to all caches, and so all other CPUs will reread the data from the main memory, which in turn will force a preliminary write from cache to main memory for the cache line of the first CPU.

An invalidated cache line does not cause a reload from RAM. A reload only occurs when the next read will result in an cache miss.

Thus "Locked" instructions (that force this mechanism, guaranteeing proper read-modify-write access even if multiple instructions access the same data are issued at the same time <overlapping execution> ) only are necessary outside a critical section protecting the data in question.

That's wrong, since a critical section does not protect any range of memory addresses.

A locking instruction most probably will invalidate the address in all caches, before reading from or writing to the specified address. Since the RAM is locked during the instruction, all other cores or processors have to wait until the end of the instruction cycle, before they can access the same address.

My conclusion is, that the said problem with linked lists results from the pointers not being defined as "volatile".

No. In a bidirectionally linked list up to 4 pointers have to be updated together, whenever an element is inserted or removed. This leaves much room for race conditions, that cannot be cured by protecting every single pointer. Instead the entire chain must be protected, by a MUTEX or other synchronization means. And then it's only a *convention*, which object or memory block shall be protected by a MUTEX, no memory barrier prevents access without obtaining the MUTEX first. Kind of a memory barrier can be established by putting the list object (head) into a TThreadList, *provided that* no code will retain references to list elements after releasing the list object.

And I really don't know how this could be cured in Pascal other than doing ASM. (I was not aware of this problem and I feel it should be discussed in the FPC mailing list.)

It's not a matter of the language, when a thread does *not* aquire a lock before accessing the related resource. It's simply a design flaw, when some piece of code does not obey the established rules.

DoDi

Reply by email

Andrew Brunner
to Michael Schnell: I fully agree. With the RTL/LCL, the MUTEX is encapsulated in the TCtriticalSection…
Michael Schnell wrote
But the original claim was that the implementation with Critical sections failed on a multi core engine and interlocked instructions helped. This is why I suggested that there is some kind of bug.

LOL I don't recall you ever asking specifics on my implementation. You have indeed made gross assumptions regardless of design.

"The Engine" doesn't have cores. It's an application written in Lazarus and proudly compiled with FPC and worked flawlessly on Windows/Ubuntu32/64 untill I upgraded from a 3 core to a 6 core. During stress tests - I watched graphically under each core, using AWN widgets (1 display per core) code execution went from core to core instead of staying locked.

While my linked list was headed by a critical section, that head was there only by design for general use and as vestigial for my particular instance. Keep in mind, there was no re-entrancy with this particular link-list instance.
I had headed it with critical sections there for two reasons.

1) it was vestige from a non-adapted - general purpose link list - and were always allowed access b/c the same thread was accessing.
2) if I ever wanted to re-use the component, I would still need that thread barrier to block re-entrance.

So to bring this to a conclusion, the Critical section did not ensure code order of execution when run on the multi-core system. And by using InterlockedExhchange we can be assured that variables are valid to other cores when the event of a core switch occurred - which resolved the stale values problem I was experiencing.

Reply by email

Andrew Brunner
to Michael Schnell: I fully agree. With the RTL/LCL, the MUTEX is encapsulated in the TCtriticalSection…
Michael Schnell wrote 10 lines
I fully agree. With the RTL/LCL, the MUTEX is encapsulated in the TCtriticalSection Object (one MUTEX per instance. And of course, here, a single instance is necessary to be used for all accesses to the pointers). And as the Mutex already contains the Full Fence memory barrier and (as discussed over in the fpc list) the function calls to Enter and Leave prevents the compiler from caching any of the intermediate pointer values in registers at a wrong point in time, I don't see why CriticalSection would not be the correct way to go and work as expected. (OTOH using atomic interlocked ASM ?instructions does not help as all pointers need to be updated in a single atomic operation).

Your assumption would be incorrect. The system doesn't do anything but decrease the spincount of the criticalsection object to make sure the variable is valid. As stated before by numerous people, a CriticalSection does not apply to variable assignments. It just blocks entrance to code blocks unit the lock is released.

But the original claim was that the implementation with Critical sections failed on a multi core engine and interlocked instructions helped.

It was an claim. It is an assertion. It's cause - due to core cache as documented on wikipedia.

This is why I suggested that there is some kind of bug.

You're free to suggest anything. Just be prepared to learn or teach - but back it up with facts no opinions.

Reply by email

José Mejuto
to Andrew Brunner

Hello Lazarus-List,

Tuesday, June 28, 2011, 6:44:17 PM, you wrote:

I can only talk about Win x86, so things could be different in other OS.

AB> Your assumption would be incorrect. The system doesn't do anything AB> but decrease the spincount of the criticalsection object to make sure AB> the variable is valid. As stated before by numerous people, a AB> CriticalSection does not apply to variable assignments. It just AB> blocks entrance to code blocks unit the lock is released.

In Win a Critical section do more things than increase, decrease the recursion count, if first try to detect the Critical adquisition using a memory barrier/atomic (exchange). If adquire fails it "spins", not exactly spins but valid for this text, until it success.

The try to adquire imposes a non reorder and cache coherence across threads, cores and processors. As much the critical spin to lock the critical section CPU performance is degradated due constantly memory fences.

*** This will never work as thread 2 does not use the protection mechanism expected by thread 1.

Thread/core/processor 1
-----------------------
while true do begin
  Critical.Enter;
  a:=a+1;
  b:=a;
  Critical.Leave;
end;
Thread/core/processor 2
-----------------------
while true do begin
  if ab then Raise Exception.Create('KBOOM!');
end;
*** This one must work
Thread/core/processor 2
-----------------------
while true do begin
  Critical.Enter;
  if ab then Raise Exception.Create('KBOOM!');
  Critical.Leave;
end;

If the second one will not work in a n-code processor, or SMP, please tell me why not. Of course the performance will be quite poor.

Best regards, Jos?

Reply by email

Hans-Peter Diettrich
to Hans-Peter Diettrich: What is "thread safe"? In how far is just FileExistsUTF8 "thread safe"? Even if the file…
Show quoted text 6 lines
Mattias Gaertner schrieb: > Only if the documentation explicitly says a method is thread safe it > is. Maybe this needs to be made more clear. Any ideas, where? What is "thread safe"?

Self-comment:

I just found a very nice description of some aspects of thread safety in http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_09_08 titled "Thread-Safety".

DoDi

Reply by email

Hans-Peter Diettrich
to Henry Vermaak: Quoting from http://msdn.microsoft.com/en-us/library/ms686355%28v=VS.85%29.aspx The…
Show quoted text 21 lines
On 28/06/11 15:47, Hans-Peter Diettrich wrote: > Henry Vermaak schrieb: > > >> You'll have to read the generated assembler for Windows critical >> sections. My hunch would be that they use memory barriers, too. > > >> > When a critical section object is owned, the only other threads affected > are the threads that are waiting for ownership in a call to > EnterCriticalSection. Threads that are not waiting are free to continue > running. > << > > I don't see anything like memory barriers here. Quoting from http://msdn.microsoft.com/en-us/library/ms686355%28v=VS.85%29.aspx The following synchronization functions use the appropriate barriers to ensure memory ordering:

Sorry for my ignorance :-(

I couldn't find a definition for memory barriers before, and confused it with persistent access locks (or visibility).

OTOH I still wonder what exact use and effects the various MB instructions have. One requirement is data consistency of the implementation of all synchronization mechanisms (mutex...), across all cores and caches, i.e.:

Functions that enter or leave critical sections Functions that signal synchronization objects Wait functions Interlocked functions

This is so obvious, that it IMO doesn't require further discussion.

Another aspect seems to be the synchronization of *all* data, in *all* caches. Is this correct, or do I expect too much?

In detail I stumbled over the remark, that these instructions signal *the compiler* (which compiler? which processor?) to do something special. This may be related to the "volatile" discussion?

DoDi

Reply by email

Hans-Peter Diettrich
to Michael Schnell: I understand that you are supposed to do CriticalSection.Enter; do something with the…
Show quoted text 17 lines
On 06/28/2011 05:33 PM, Hans-Peter Diettrich wrote: > > > A critical section (process-local MUTEX) is not related to a specific > (memory) resource, except itself, consequently it can not protect any > *other* resource. It also does not block any other thread, not waiting > for entering the critical section, so that all resources are > accessible by all threads, except the critical section (or mutex...) > itself. I understand that you are supposed to do CriticalSection.Enter; do something with the variables that are protected CriticalSection.leave; What did you think how to use them ? Of course a MUTEX can do other things, too, but here we are discussing "normal" CriticalSection use.

I suspect that some people expect too much from CriticalSection. E.g.

do something with the variables that are protected

sounds nice, but it does not hinder any other code to do something with the same variables, at the same time, *without* entering the CS. This should be made clear in some tutorial, and should be known to everybody talking about threads.

Above code snippet IMO is not enough, instead it should be encapsulated in a class that also *provides* the mentioned CriticalSection. When all critical methods of that class use above pattern internally, and the class also keeps the protected variables strictly private (see TThreadList), then we have a nice example for the correct use of critical sections or other mutexes.

DoDi

Reply by email

Hans-Peter Diettrich
to Andrew Brunner: On Tue, Jun 28, 2011 at 10:33 AM, Hans-Peter Diettrich 100% correct. That's what I've…
Show quoted text 12 lines
> In a bidirectionally linked list up to 4 pointers have to be updated > together, whenever an element is inserted or removed. This leaves much room > for race conditions, that cannot be cured by protecting every single > pointer. Instead the entire chain must be protected, by a MUTEX or other > synchronization means. And then it's only a *convention*, which object or > memory block shall be protected by a MUTEX, no memory barrier prevents > access without obtaining the MUTEX first. Kind of a memory barrier can be > established by putting the list object (head) into a TThreadList, *provided > that* no code will retain references to list elements after releasing the > list object. I had a similar issue once.

Above is my comment on your example ;-)

IMO a nice candidate for a thread-safety tutorial. It even can be extended into a less restrictive model, that allows for kind of multiple-read-exclusive-write access.

And it was solved with bringing the list under my manager/worker system so that there was only one thread accessing the linkedlist, and I used InterlockedExchange for First,Last,Next,Previous.

Why do you see a need for Interlocked updates, when only one thread can access the list at the same time?

IMO Interlocked updates are fine for self-contained values, where the use of critical sections would be overkill. But when multiple variables have to be updated without interruption (synchronously, atomically), the entire data object should be protected against concurrent access.

Show quoted text 9 lines
>> And I really don't know how this could be cured in Pascal other than doing >> ASM. (I was not aware of this problem and I feel it should be discussed in >> the FPC mailing list.) > It's not a matter of the language, when a thread does *not* aquire a lock > before accessing the related resource. It's simply a design flaw, when some > piece of code does not obey the established rules. I don't see how this is an issue of obedience. It's more of a phenomenon.

I see it as a matter of coding discipline, and how to make disobedience as impossible as possible ;-)

DoDi

Reply by email

Andrew Brunner
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 18 lines
Andrew Brunner schrieb: >> In a bidirectionally linked list up to 4 pointers have to be updated >> together, whenever an element is inserted or removed. This leaves much >> room >> for race conditions, that cannot be cured by protecting every single >> pointer. Instead the entire chain must be protected, by a MUTEX or other >> synchronization means. And then it's only a *convention*, which object or >> memory block shall be protected by a MUTEX, no memory barrier prevents >> access without obtaining the MUTEX first. Kind of a memory barrier can be >> established by putting the list object (head) into a TThreadList, >> *provided >> that* no code will retain references to list elements after releasing the >> list object. > > I had a similar issue once. Above is my comment on your example ;-)

The above comment has nothing to do with my "example". My example was the one with 2 lines of code being executed by two different cores under the same thread protected within a criticalsection.

My experience though, was shared where I "happened" to have a memory barrier in place, and experienced a problem with order or stale values that was solved by using InterlockedExchange calls.

Why do you see a need for Interlocked updates, when only one thread can access the list at the same time?

Primarily because I want to enforce core cache updates to the values.

Show quoted text 8 lines
IMO Interlocked updates are fine for self-contained values, where the use of critical sections would be overkill. But when multiple variables have to be updated without interruption (synchronously, atomically), the entire data object should be protected against concurrent access. I see it as a matter of coding discipline, and how to make disobedience as impossible as possible ;-)

Obedience is not germane to the topic of this particular issue of core cache and interlockedexhange.

Reply by email

Michael Schnell
to Hans-Peter Diettrich: Sorry for my ignorance :-( I couldn't find a definition for memory barriers before, and…
Hans-Peter Diettrich wrote
Another aspect seems to be the synchronization of *all* data, in *all* caches. Is this correct, or do I expect too much?

Not necessary (e.g.) on detecting that a cache line resides in multiple caches doing an immediate write back and invalidating for all other caches a cache line that is written to in one cache would forces a synchronization without too much overhead. AFAIK certain processors provide a dedicated fast inter-cache bus for such operations.

I suppose how exactly this is done depends on the CPU manufacturer.

-Michael

Reply by email

Michael Schnell
to Hans-Peter Diettrich: I suspect that some people expect too much from CriticalSection. E.g. sounds nice, but it…
Hans-Peter Diettrich wrote
sounds nice, but it does not hinder any other code to do something with the same variables, at the same time, *without* entering the CS.

Of course a CS only makes sense if all code accessing the data in question is done using the same CS. So "without" is absolutely forbidden. (Of course in fact a TCriticalSection instance is used to protect a group of "critical code sequences").

-Michael

Reply by email

Michael Schnell
to Andrew Brunner: LOL I don't recall you ever asking specifics on my implementation. You have indeed made…
Andrew Brunner wrote
On Tue, Jun 28, 2011 at 9:59 AM, Michael Schnell wrote: > This is why I suggested that there is some kind of bug. LOL I don't recall you ever asking specifics on my implementation.

I did not claim that the big is in your implementation,. It might be in the RTL/LCL, some library, the Kernel, the hardware, you name it.

But correct Posix compliant code is supposed to work on hardware with any count of cores. So there seems to be a bug _somewhere_.

-Michael

Reply by email

Michael Schnell
to José Mejuto: I can only talk about Win x86, so things could be different in other OS. AB> Your…
Jos? Mejuto wrote 11 lines
*** This one must work Thread/core/processor 2 ----------------------- while true do begin Critical.Enter; if ab then Raise Exception.Create('KBOOM!'); Critical.Leave; end; If the second one will not work in a n-code processor, or SMP, please tell me why not. Of course the performance will be quite poor.

Did you experience that it does not work ? IMHO that would be really ban news.

-Michael

Reply by email

Michael Schnell
to Hans-Peter Diettrich: Self-comment: I just found a very nice description of some aspects of thread safety in…
Hans-Peter Diettrich wrote 6 lines
I just found a very nice description of some aspects of thread safety in http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_09_08 titled "Thread-Safety".

Great.

Niche background information on Posix.

But it does not help regarding the issue of defining a thread-safety paradigm for classes.

-Michael

Reply by email

Andrew Brunner
to Michael Schnell: I did not claim that the big is in your implementation,. It might be in the RTL/LCL, some…
Michael Schnell wrote
But correct Posix compliant code is supposed to work on hardware with any count of cores. So there seems to be a bug _somewhere_. From what I observed and read, using Interlocked assignments or

Compare and Swap was designed to explicitly resolve the issue of stale core cache values and even code execution with regard to such assignments. I don't see anything in POSIX documentation that explicitly ties execution order and core cache - as this is low level as it gets.

It should be noted that core switching is done so without application awareness.

I would love nothing more than to be able to have critical section force a "core lock" but I think this goes well beyond the scope of the engineering intention of CrticialSections.

Reply by email

José Mejuto
to Michael Schnell: Did you experience that it does not work ? IMHO that would be really ban news. -Michael

Hello Lazarus-List,

you wrote 11 lines
> *** This one must work > Thread/core/processor 2 > ----------------------- > while true do begin > Critical.Enter; > if ab then Raise Exception.Create('KBOOM!'); > Critical.Leave; > end; > > If the second one will not work in a n-code processor, or SMP, please > tell me why not. Of course the performance will be quite poor.

MS> Did you experience that it does not work ? IMHO that would be really ban MS> news.

No, exactly the opposite, I do not see how it could fail about memory order access, cache coherence, ...

Best regards, Jos?

Reply by email

Lukasz Sokol
to Michael Schnell: Great. Niche background information on Posix. But it does not help regarding the issue of…
Michael Schnell wrote 12 lines
On 06/28/2011 08:14 PM, Hans-Peter Diettrich wrote: > > > I just found a very nice description of some aspects of thread safety in > http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_09_08 > titled "Thread-Safety". Great. Niche background information on Posix. But it does not help regarding the issue of defining a thread-safety paradigm for classes.

How is the 'thread safety for classses' different from thread safety for any other code ?

L.

Reply by email

Hans-Peter Diettrich
to Lukasz Sokol
Show quoted text 15 lines
On 29/06/2011 16:11, Michael Schnell wrote: > On 06/28/2011 08:14 PM, Hans-Peter Diettrich wrote: >> >> I just found a very nice description of some aspects of thread safety in >> http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_09_08 >> titled "Thread-Safety". > Great. > > Niche background information on Posix. > > But it does not help regarding the issue of defining a thread-safety paradigm for classes. > How is the 'thread safety for classses' different from thread safety for any other code ?

Thread-safety has many facettes. An item may be safe in one aspect, e.g. not using global variables, but unsafe in other aspects.

Objects (classes) add further topics to the list of items, that make up "thread-safety" in general.

During the various discussions I got the impression, that thread-safety only can be a headline or keyword, that leads to a detailed description of thread-related properties or behaviour of the described item.

DoDi

Reply by email

Lukasz Sokol
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote
Lukasz Sokol schrieb:

[...]

Show quoted text 6 lines
> > How is the 'thread safety for classses' different from thread > safety for any other code ? Thread-safety has many facettes. An item may be safe in one aspect, e.g. not using global variables, but unsafe in other aspects.

If it is unsafe in other aspects then it is unsafe, right? (modulo what you actually need, but AFAIR there is not much too pick&choose from, because they are related and some of them imply others ?)

Objects (classes) add further topics to the list of items, that make up "thread-safety" in general.

After compilation, it's just code, isn't it?
Classes may have the 'hidden' variables but they're not 'hidden' to the OS/CPU ?

Show quoted text 6 lines
During the various discussions I got the impression, that thread-safety only can be a headline or keyword, that leads to a detailed description of thread-related properties or behaviour of the described item.

AFAIR, code (whatever way you write it) can either BE safe or NOT, no half measyres here - any one of the 'properties' vel 'aspects' not complied with, and you can't name your code thread-safe.

It may be a headline or keyword, but it should list ALL the things one need to be aware of when writing multi-threaded code?

That's my view.

DoDi

Reply by email

Michael Schnell
to Lukasz Sokol: [...] If it is unsafe in other aspects then it is unsafe, right? (modulo what you…
Lukasz Sokol wrote
After compilation, it's just code, isn't it?

Yep but the programmer that writes the code using an existing object and reading it's docs does not see the code after compilation. He is inclined to consider the functions of multiple instances of a class to be unrelated code which might or might not be appropriate, depending on the classes internals. (Or anther programmer thinks the code is related, which might in fact be too restrictive.)

-Michael

Reply by email

Michael Schnell
to Lukasz Sokol: [...] If it is unsafe in other aspects then it is unsafe, right? (modulo what you…
Lukasz Sokol wrote
AFAIR, code (whatever way you write it) can either BE safe or NOT, no half measyres here - any one of the 'properties' vel 'aspects' not complied with, and you can't name your code thread-safe.

A function easily can be thread safe _only_ if a parameter of same is different for each thread:

var
  a array [0...10] of Integer;
Function x(i);
begin
   a[i] := a[i] + 1;
end;

A very likely case with the hidden self parameter of class instances.

-Michael

Reply by email

Hans-Peter Diettrich
to Lukasz Sokol: [...] If it is unsafe in other aspects then it is unsafe, right? (modulo what you…
Show quoted text 6 lines
> Objects (classes) add further topics to the list of items, that make > up "thread-safety" in general. After compilation, it's just code, isn't it? Classes may have the 'hidden' variables but they're not 'hidden' to the OS/CPU ?

Objects include information, that may be subject to race conditions, deadlocks and other unwanted things. A "thread-safe" definition for procedures covers nothing of what applies to thread-safe objects.

DoDi

Reply by email