Solved

1 MDI Form, 2 Indy Reader Threads, 1 INIFile.  How do I make it thread safe?

Posted on 2004-09-22
7
564 Views
Last Modified: 2012-06-21
Greetings,

This question spawns off of from another question...
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21136526.html

Right now I have an Indy Reader Thread, that spawns a 2nd Indy Reader Thread to a 2nd Login Server.  Both threads need information from an INI file.  Right now, the INI file is a property of the form which uses the INI also.  I have tried using a critical section around all the reads to it, but it still does not work properly.

Here is a link to the source that I am using...
http://www.datazap.net/ftp/werehamster/MyBot/3.zip

Please, I need example source of how to use a single INI file between multible threads and a form.  This is a critical part of my program and is only used during login so performance isn't an issue.
0
Comment
Question by:werehamster-
  • 3
  • 2
7 Comments
 
LVL 10

Expert Comment

by:Jacco
ID: 12135846
It would be a good decision to separate the TWerebot from TBNLSReader and TBNETReader. It is always dangerous to have them in one unit since they can then mess with each other private parts <G> to easily.

At this moment the use of the INI file is threadsafe because you only use it in the FormCreate of TWereBot if you want to start using it from one of the threads as well it might be a problem.

You could make a threadsafe wrapper around the INI:

unit Unit1;

interface

uses
  IniFiles, SysUtils;

type
  TSafeIniFile = class(TIniFile)
  private
    fGuard: TMultiReadExclusiveWriteSynchronizer;
  public
    constructor Create(const FileName: string);
    destructor Destroy; override;
    function ReadString(const Section, Ident, Default: string): string; override;
    procedure WriteString(const Section, Ident, Value: string); override;
  end;

implementation

{ TSafeIniFile }

constructor TSafeIniFile.Create(const FileName: string);
begin
  inherited Create(FileName);
  fGuard := TMultiReadExclusiveWriteSynchronizer.Create;
end;

destructor TSafeIniFile.Destroy;
begin
  fGuard.Free;
  inherited Destroy;
end;

function TSafeIniFile.ReadString(const Section, Ident, Default: string): string;
begin
  fGuard.BeginRead;
  try
    Result := inherited ReadString(Section, Ident, Default);
  finally
    fGuard.EndRead;
  end;
end;

procedure TSafeIniFile.WriteString(const Section, Ident, Value: string);
begin
  fGuard.BeginWrite;
  try
    inherited WriteString(Section, Ident, Value);
  finally
    fGuard.EndWrite;
  end;
end;

end.

You should also protect:

    procedure ReadSection(const Section: string; Strings: TStrings); override;
    procedure ReadSections(Strings: TStrings); override;
    procedure ReadSectionValues(const Section: string; Strings: TStrings); override;

inside BeginRead/EndRead's and

    procedure EraseSection(const Section: string); override;
    procedure DeleteKey(const Section, Ident: String); override;
    procedure UpdateFile; override;

inside BeginWrite/EndWrites

Now all threads including the forms main thread can share in instance of the INIFile

Regards Jacco

0
 

Author Comment

by:werehamster-
ID: 12139408
Hmm, never used this before...

TMultiReadExclusiveWriteSynchronizer;

I assume it is better than TCriticalSection?

So basically I treat is as .enter and .leave, but for file access stuff?
0
 
LVL 10

Accepted Solution

by:
Jacco earned 500 total points
ID: 12140288
TMultiReadExclusiveWriteSynchronizer is a nifty thing in SysUtils:

It allows multiple threads to enter the section using BeginRead but a BeginWrite can only enter when all readers (except the threads issuing the BeginWrite itself) have to be passed the EndRead point. When the write is passed the BeginWrite point only this thread can use BeginRead and go in. All other reader will wait at the BeginRead point.

It is not better that the TCriticalSection, it allows more threads to read data but only one to write.

It is not only for file access but for all shared data. The contract is that after the EndWrite the data should not be left in an unreadable state because directly after it waiting threads might go in and read stuff.

Regards Jacco
0
 
LVL 10

Expert Comment

by:Jacco
ID: 13390077
I think I gave a correct solution.
0
 

Author Comment

by:werehamster-
ID: 13413048
Shrug, did it myself.  :)
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi 2 68
LAN or WAN ? 11 95
Is anyone willing to have a look through this code and help debug? 25 82
How to save the image in the .cds File ClientDataSet? 1 22
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

792 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question