trouble: 2 threads accessing simultaneous the same item of a

Ask your beginner questions here.

trouble: 2 threads accessing simultaneous the same item of a

Postby fl4shc0d3r » Sun Sep 10, 2017 5:59 pm

I have this code below that send email based in queue threads but if not pause (eg: Sleep(1000)) by a certain time, two threads try access the same item of queue simultaneous.

Someone know how solve this trouble?

Code: Select all
uses
  System.Types, Generics.Collections, IdMessage;

type
  TThreadItem = class;
  TThreadList = TObjectList;
  TMessageItem = TIdMessage;
  TMessageQueue = TThreadedQueue;

  TThreadPool = class
  private
    FQueue: TMessageQueue;
    FThreads: TThreadList;
  public
    constructor Create(Count: Integer);
    destructor Destroy; override;
    procedure Shutdown;
    property Queue: TMessageQueue read FQueue;
  end;

  TThreadItem = class(TThread)
  private
    FQueue: TMessageQueue;
  protected
    procedure Execute; override;
  public
    constructor Create(Queue: TMessageQueue); reintroduce;
  end;

implementation

{ TThreadPool }

constructor TThreadPool.Create(Count: Integer);
var
  I: Integer;
  Thread: TThreadItem;
begin
  inherited Create;
  { this will create thread queue that will wait for push and pop of its items INFINITE
    time; that's useful for thread sleeping }
  FQueue := TMessageQueue.Create;
  FThreads := TThreadList.Create;

  for I := 0 to Count-1 do
  begin
    Thread := TThreadItem.Create(FQueue);
    FThreads.Add(Thread);
  end;
end;

destructor TThreadPool.Destroy;
begin
  Shutdown;
  FThreads.Free;
  FQueue.Free;
  inherited;
end;

procedure TThreadPool.Shutdown;
var
  Thread: TThreadItem;
  Message: TMessageItem;
begin
  { signal threads for termination }
  for Thread in FThreads do
    Thread.Terminate;
  { shutdown the queue to "unlock" sleeping threads }
  FQueue.DoShutDown;
  { free all the unprocessed enqueued message items }
  Message := FQueue.PopItem;
  while Assigned(Message) do
  begin
    Message.Free;
    Message := FQueue.PopItem;
  end;
end;

{ TThreadItem }

constructor TThreadItem.Create(Queue: TMessageQueue);
begin
  inherited Create;
  FQueue := Queue;
end;

procedure TThreadItem.Execute;
var
  Message: TMessageItem;
begin
  { <- create and setup Indy sending object here }
  try
    while not Terminated do
      { here we'll wait for INFINITE time for an item or until queue is shutted down;
        you should consider checking for error state as well }
      if FQueue.PopItem(Message) = wrSignaled then
      try
        { <- send the Message through the Indy sending object here }
      finally
        Message.Free;
      end;
  finally
    { <- destroy Indy sending object here }
  end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////

{ Possible usage: }

Pool := TThreadPool.Create(2); { <- create 2 threads }
for I := 0 to 99 do
begin
  Message := TMessageItem.Create(nil);
  Message.Subject := 'Message subject';
  ...
  Pool.Queue.PushItem(Message);
end;
fl4shc0d3r
 
Posts: 28
Joined: Fri Jan 20, 2017 3:10 am
Reputation point: -1

Re: trouble: 2 threads accessing simultaneous the same item

Postby Vrtule » Sun Sep 10, 2017 6:29 pm

Sleep/wakeup SHOULD NEVER be used for synchronizing accesses to a shared variable. The reason is that these operations are not atomic and make the program dependent on the processor performance, mood of the thread scheduler etc. (and one of the basic rules of the critical section says that you should never ever do this).

Instead, use mutexes (CreateMutex, WaitForXxxObject, ReleaseMutex, CloseHandle) or critical sections (InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection). The trick is that either a mutex, or a critical section, can be owned at most by one thread at any time moment. And that is exactly what you need, since at most one of your threads should send the message (precisely, extract it from the queu) at once.

IIRC, Delphi has an unit called SyncObj which contains a wrapper around Windows criticalsections, so you do not need to use Windows API directly.
User avatar
Vrtule
 
Posts: 413
Joined: Sat Mar 13, 2010 9:14 pm
Location: Czech Republic
Reputation point: 92

Re: trouble: 2 threads accessing simultaneous the same item

Postby Brock » Mon Sep 11, 2017 3:27 pm

Vrtule is right however if you want to use WinAPI directly it's only a few lines of code and you don't need classes or OO for it.

Code: Select all
var
   CritSec: RTL_CRITICAL_SECTION;


procedure EnterLock;
begin
    EnterCriticalSection(CritSec);
end;


procedure LeaveLock;
begin
    LeaveCriticalSection(CritSec);
end;


procedure AccessMutualResource;
begin
       EnterLock;
   try
   // Access mutual resource here
   finally
       LeaveLock;
   end;
end;


initialization
     InitializeCriticalSection(CritSec);


finalization
     DeleteCriticalSection(CritSec);
Accept nothing less than STATUS_SUCCESS
User avatar
Brock
 
Posts: 200
Joined: Wed Apr 28, 2010 3:13 am
Location: Navarre, Florida USA
Reputation point: 19

Re: trouble: 2 threads accessing simultaneous the same item

Postby fl4shc0d3r » Tue Sep 19, 2017 2:22 pm

Brock wrote:Vrtule is right however if you want to use WinAPI directly it's only a few lines of code and you don't need classes or OO for it.

Code: Select all
var
   CritSec: RTL_CRITICAL_SECTION;


procedure EnterLock;
begin
    EnterCriticalSection(CritSec);
end;


procedure LeaveLock;
begin
    LeaveCriticalSection(CritSec);
end;


procedure AccessMutualResource;
begin
       EnterLock;
   try
   // Access mutual resource here
   finally
       LeaveLock;
   end;
end;


initialization
     InitializeCriticalSection(CritSec);


finalization
     DeleteCriticalSection(CritSec);


Ok, solved.
fl4shc0d3r
 
Posts: 28
Joined: Fri Jan 20, 2017 3:10 am
Reputation point: -1

Re: trouble: 2 threads accessing simultaneous the same item

Postby EP_X0FF » Fri Sep 22, 2017 3:34 am

fl4shc0d3r wrote:Ok, solved.



Copy-pasted you mean. Next time do your outstanding quality topics in appreciate forum for newbie questions.
Ring0 - the source of inspiration
User avatar
EP_X0FF
Global Moderator
 
Posts: 4752
Joined: Sun Mar 07, 2010 5:35 am
Location: Russian Federation
Reputation point: 562


Return to Newbie Questions

Who is online

Users browsing this forum: No registered users and 2 guests