Board index » delphi » Connection.Writeln from VCL-Main-Thread and Client-Thread

Connection.Writeln from VCL-Main-Thread and Client-Thread

Hi,

my server has the following code on timer-event:

        List := tcpServer.Threads.LockList;
        try
          for i := 0 to List.Count -1 do
          try
            TIdPeerThread(List.Items[i]).Connection.WriteLn('something');
          except
            TIdPeerThread(List.Items[i]).Stop;
          end;
        finally
          tcpServer.Threads.UnlockList;
        end;

Sometimes one of the client-threads of my server writes binary-data to the
client, like

       IdTCPClient.WriteStream(FileStream, True, True);

Sometimes when it overlapps I find the word 'something' in my binary-data,
how can I avoid it?

cu Carsten.

 

Re:Connection.Writeln from VCL-Main-Thread and Client-Thread


The brute force way is to lock the thread list before any write, this will
insure only one thread is writing at a time.

The better approach would be to put a critical section in for each active
connection and lock that.  This would insure that a long transfer to one
client did not hold up everyone else while also insuring that you do not
corrupt the stream.  If you take  this approach you will need to be careful
if any other resources are locked by your write code so that you don't
deadlock.  If your app primarily does broadcasts use the 1st solution since
it is the safest and easiest.

Hope this helps,
Jeff

Quote
"Casi" <faltic...@freenet.de> wrote in message

news:3e75032d@newsgroups.borland.com...
Quote
> Hi,

> my server has the following code on timer-event:

>         List := tcpServer.Threads.LockList;
>         try
>           for i := 0 to List.Count -1 do
>           try
>             TIdPeerThread(List.Items[i]).Connection.WriteLn('something');
>           except
>             TIdPeerThread(List.Items[i]).Stop;
>           end;
>         finally
>           tcpServer.Threads.UnlockList;
>         end;

> Sometimes one of the client-threads of my server writes binary-data to the
> client, like

>        IdTCPClient.WriteStream(FileStream, True, True);

> Sometimes when it overlapps I find the word 'something' in my binary-data,
> how can I avoid it?

> cu Carsten.

Re:Connection.Writeln from VCL-Main-Thread and Client-Thread


Hi Jeff,

your second suggestion sounds good, but how can I program a critical section
only for each active connection ?
if I do something like this:

                CriticalSect.Acquire;
                try
                   AThread.Connection.Writeln('....');
                Finally
                  CriticalSect.Release;
                end;

The critical section will be locked for all client threads, and not only for
the main-vcl thread.
Target will be to lock the writing of the client only against the
timer-event
of the main-vcl thread.
I don't know how to do this.

cu Carsten.

"JeffS" <j...@vortic.com> schrieb im Newsbeitrag
news:3e7508a7$1@newsgroups.borland.com...

Quote
> The brute force way is to lock the thread list before any write, this will
> insure only one thread is writing at a time.

> The better approach would be to put a critical section in for each active
> connection and lock that.  This would insure that a long transfer to one
> client did not hold up everyone else while also insuring that you do not
> corrupt the stream.  If you take  this approach you will need to be
careful
> if any other resources are locked by your write code so that you don't
> deadlock.  If your app primarily does broadcasts use the 1st solution
since
> it is the safest and easiest.

> Hope this helps,
> Jeff

> "Casi" <faltic...@freenet.de> wrote in message
> news:3e75032d@newsgroups.borland.com...
> > Hi,

> > my server has the following code on timer-event:

> >         List := tcpServer.Threads.LockList;
> >         try
> >           for i := 0 to List.Count -1 do
> >           try

TIdPeerThread(List.Items[i]).Connection.WriteLn('something');

- Show quoted text -

Quote
> >           except
> >             TIdPeerThread(List.Items[i]).Stop;
> >           end;
> >         finally
> >           tcpServer.Threads.UnlockList;
> >         end;

> > Sometimes one of the client-threads of my server writes binary-data to
the
> > client, like

> >        IdTCPClient.WriteStream(FileStream, True, True);

> > Sometimes when it overlapps I find the word 'something' in my
binary-data,
> > how can I avoid it?

> > cu Carsten.

Re:Connection.Writeln from VCL-Main-Thread and Client-Thread


Quote
Casi <faltic...@freenet.de> wrote in message

news:3e763772@newsgroups.borland.com...

Quote
> Hi Jeff,

> your second suggestion sounds good, but how can I program a
critical section
> only for each active connection ?
> if I do something like this:

>                 CriticalSect.Acquire;
>                 try
>                    AThread.Connection.Writeln('....');
>                 Finally
>                   CriticalSect.Release;
>                 end;

> The critical section will be locked for all client threads, and not
only for
> the main-vcl thread.
> Target will be to lock the writing of the client only against the
> timer-event
> of the main-vcl thread.

No.  You have to acquire the CS whatever thread wants to write.  Each
peer thread should create it's own CS upon connection & free it on
disconnect.  You could override 'writeLn' to acquire this CS &
release it afterwards, or you could use another thread method,
'safeWriteLn' say, that acquires the CS, performs the writeLn & then
releases the CS.  Any thread that needs to write - main, the peer
thread connected to the client, or some other thread, should only use
methods that acquire/release the CS instance within each peer thread.

If each peer thread has it' own CS, there is no problem.  A locked
write to one client does not prevent a locked write to another
client - they are different CS instances.

Rgds,
Martin

Re:Connection.Writeln from VCL-Main-Thread and Client-Thread


Martin's answer spells it out very well.  The only thing I would add is to
be very careful that the code you write does not need access to any shared
resources after you aquire the lock for a given connection.  Since you  seem
to be a bit unclear on threading and critical sections I just wanted to warn
you that it is best to create the entire message that will be sent,
accessing any global data you need,  and then lock the connection.  If this
is done using local variables to create the message and all global data
realeased then you are thread safe when you enter the critical section for
the write.  Otherwise even though the write locks are independant your
access to global data could deadlock you as two threads wait for the same
data.

Quote
"Martin James" <mjames_fal...@dial.pipex.com> wrote in message

news:3e763b7c@newsgroups.borland.com...
Quote

> Casi <faltic...@freenet.de> wrote in message
> news:3e763772@newsgroups.borland.com...
> > Hi Jeff,

> > your second suggestion sounds good, but how can I program a
> critical section
> > only for each active connection ?
> > if I do something like this:

> >                 CriticalSect.Acquire;
> >                 try
> >                    AThread.Connection.Writeln('....');
> >                 Finally
> >                   CriticalSect.Release;
> >                 end;

> > The critical section will be locked for all client threads, and not
> only for
> > the main-vcl thread.
> > Target will be to lock the writing of the client only against the
> > timer-event
> > of the main-vcl thread.

> No.  You have to acquire the CS whatever thread wants to write.  Each
> peer thread should create it's own CS upon connection & free it on
> disconnect.  You could override 'writeLn' to acquire this CS &
> release it afterwards, or you could use another thread method,
> 'safeWriteLn' say, that acquires the CS, performs the writeLn & then
> releases the CS.  Any thread that needs to write - main, the peer
> thread connected to the client, or some other thread, should only use
> methods that acquire/release the CS instance within each peer thread.

> If each peer thread has it' own CS, there is no problem.  A locked
> write to one client does not prevent a locked write to another
> client - they are different CS instances.

> Rgds,
> Martin

Re:Connection.Writeln from VCL-Main-Thread and Client-Thread


Hi Jeff,
Hi Martin,

both solutions are good, but how can I create a critical section or override
the writeln-method,
I have no thread-class, the threads are all created by tcpServer. Please
refer to my following
example, where should I define the CriticalSect variable ??

cu Carsten.

procedure TfrmMain.tcpServerExecute(AThread: TIdPeerThread);
begin
  try
    strMsg := AThread.Connection.ReadLn;
    ptrClient := Pointer(AThread.Data);

    strCMD := ExtractCMD(strMsg);

    if strCMD =  .... then begin

         CriticalSect.Acquire;
          try
             AThread.Connection.Writeln(...);
          Finally
            CriticalSect.Release;
          end;

"JeffS" <j...@vortic.com> schrieb im Newsbeitrag
news:3e764b1c$1@newsgroups.borland.com...

Quote
> Martin's answer spells it out very well.  The only thing I would add is to
> be very careful that the code you write does not need access to any shared
> resources after you aquire the lock for a given connection.  Since you
seem
> to be a bit unclear on threading and critical sections I just wanted to
warn
> you that it is best to create the entire message that will be sent,
> accessing any global data you need,  and then lock the connection.  If
this
> is done using local variables to create the message and all global data
> realeased then you are thread safe when you enter the critical section for
> the write.  Otherwise even though the write locks are independant your
> access to global data could deadlock you as two threads wait for the same
> data.

> "Martin James" <mjames_fal...@dial.pipex.com> wrote in message
> news:3e763b7c@newsgroups.borland.com...

> > Casi <faltic...@freenet.de> wrote in message
> > news:3e763772@newsgroups.borland.com...
> > > Hi Jeff,

> > > your second suggestion sounds good, but how can I program a
> > critical section
> > > only for each active connection ?
> > > if I do something like this:

> > >                 CriticalSect.Acquire;
> > >                 try
> > >                    AThread.Connection.Writeln('....');
> > >                 Finally
> > >                   CriticalSect.Release;
> > >                 end;

> > > The critical section will be locked for all client threads, and not
> > only for
> > > the main-vcl thread.
> > > Target will be to lock the writing of the client only against the
> > > timer-event
> > > of the main-vcl thread.

> > No.  You have to acquire the CS whatever thread wants to write.  Each
> > peer thread should create it's own CS upon connection & free it on
> > disconnect.  You could override 'writeLn' to acquire this CS &
> > release it afterwards, or you could use another thread method,
> > 'safeWriteLn' say, that acquires the CS, performs the writeLn & then
> > releases the CS.  Any thread that needs to write - main, the peer
> > thread connected to the client, or some other thread, should only use
> > methods that acquire/release the CS instance within each peer thread.

> > If each peer thread has it' own CS, there is no problem.  A locked
> > write to one client does not prevent a locked write to another
> > client - they are different CS instances.

> > Rgds,
> > Martin

Other Threads