I create a mutex at the start of the my application, primarily to prevent running 2 instances of same application.
if CreateMutex(nil,false,'Proton Studio') = 0 then
RaiseLastOSError;
if GetLastError = ERROR_ALREADY_EXISTS then exit;
However, when I reconfigure my application I need to release the mutex before the application is closed in order to start a short program which will then restart my application.
hw := OpenMutex(MUTEX_ALL_ACCESS, false, 'Proton Studio');
if ReleaseMutex(hw)then begin
if ShellExecute(application.Handle, 'open',
Pchar('StudioRestart.exe'), PChar(Application.ExeName),'', SW_SHOWNORMAL) > 32 then
fmIDEMain.Close
else
ShowMessage('Unable to Restart, please close and restart manually')
end
OpenMutex returns a handle but when I call ReleaseMutex the function returns false. How should I close this mutex?
You seem to use the existence of the mutex as the criterion to decide whether the process already runs and not who owns the mutex. ReleaseMutex is used to give up ownership of a mutex if you currently own it. But your code doesn't actually retrieve ownership of the mutex anywhere.
I see these ways towards solving your problem:
Destroy mutex instead of trying to release it.
Instead of using ReleaseMutex, use CloseHandle to destroy the mutex. If you are the only one holding a handle to the mutex, it will be gone afterwards.
For this purpose, remember the original handle returned by CreateMutex and don't open the mutex a second time.
Use mutexes as intended
Instead of using the mere existing of the mutex, try to obtain ownership by calling WaitForSingleObject on it. You can then release it by calling ReleaseMutex.
External program should wait (my preferred method)
Have the external program wait until the old instance of the application was fully terminated before trying to start a new instance.
Related
I am working on the project where I communicate with another device over COM port.
For incoming data I am using VaComm1RXchar event, there I store the message into the array and increment msgIndex which represents number of messages.
Then I call the function where I work with this message.
Inside this function is this timeout cycle where I wait for this message:
while MsgIndex < 1 do
begin
stop := GetTickCount;
if (stop - start)> timeout then
begin
MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
exit(false);
end;
sleep(10);
end;
The strange thing for me is that, when have it like this above then it always end with timeout. But when I put on there before this while cycle a ShowMessage('Waiting') then It works correcly.
Does anyone know what can caused this and how can I solve it? Thanks in advance!
We can deduce that the VaComm1RXchar event is a synchronous event and that by blocking your program in a loop you are preventing the normal message processing that would allow that event to execute.
Showing a modal dialog box, on the other hand, passes message handling to that dialog so the message queue is properly serviced and your Rx events and handled normally.
You can be certain this is the case if this also works (please never write code like this - it's just to prove the point):
while MsgIndex < 1 do begin
stop := GetTickCount;
if (stop - start)> timeout then begin
MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
exit(false);
end;
Application.ProcessMessages; // service the message queue so that
sleep(10); // your Rx event can be handled
end;
If there is a lesson here it is that RS-232 communication really needs to be done on a background thread. Most all implementations of "some chars have been received" events lead to dreadful code for the very reason you are discovering. Your main thread needs to be free to process the message that characters have been received but, at the same time, you must have some parallel process that is waiting for those received characters to complete a cogent instruction. There does not exist a sensible solution in an event-driven program to both manage the user interface and the communication port at the same time on one thread.
A set of components like AsyncPro**, for example, wrap this functionality into data packets where synchronous events are used but where the components manage start and end string (or bytes) detection for you on a worker thread. This removes one level of polling from the main thread (ie: you always get an event when a complete data packet has arrived, not a partial one). Alternatively, you can move the communication work to a custom thread and manage this yourself.
In either case, this is only partly a solution, of course, since you still cannot stick to writing long procedural methods in synchronous event handlers that require waiting for com traffic. The second level of polling, which is managing a sequence of complete instructions, will still have you needing to pump the message queue if your single procedure needs to react to a sequence of more than one comport instruction. What you also need to think about is breaking up your long methods into shorter pieces, each in response to specific device messages.
Alternatively, for heavily procedural process automation, it is also often a good idea to move that work to a background thread as well. This way your worker threads can block on synchronization objects (or poll in busy loops for status updates) while they wait for events from hardware. One thread can manage low level comport traffic, parsing and relaying those commands or data packets, while a second thread can manage the higher level process which is handling the sequence of complete comport instructions that make up your larger process. The main thread should primarily only be responsible for marshalling these messages between the workers, not doing any of the waiting itself.
See also : I do not understand what Application.ProcessMessages in Delphi is doing
** VAComm may also support something like this, I don't know. The API and documentation are not publicly available from TMS for ASync32 so you'll need to consult your local documentation.
What happens is that a modal message loop executes when the dialog is showing. That this message loop changes behaviour for you indicates that your communications with the device require the presence of a message loop.
So the solution for you is to service the message queue. A call to Application.ProcessMessages in your loop will do that, but also creates other problems. Like making your UI become re-entrant.
Without knowing more about your program, I cannot offer more detailed advice as to how you should solve this problem.
I'm new to this so sorry in case my question seems to be silly, I'm writing a Delphi program in which I'm running a list of external executables though multiple threads in a queue and waiting for them to finish using CreateProcess like:
CreateProcess(Pchar(NotepadExe), Nil, Nil, Nil,
False, NORMAL_PRIORITY_CLASS,
Nil, Nil, StartupInfo,ProcessInfo),
and
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
now the programs I called are performing lengthy jobs, so in case my program got closed while the external executables are still running, is there an easy way to regain access to the processes and waiting for them again? and what about the case when some of them are finished already?
I did sort of what #SertacAkyuz suggested, and it works
During execution I add the current process id to a file using
GetCurrentProcessId
When I start my program I read from the file the saved processIds then determine which of the currently running processes are children which I already ran, afterwards I create a thread to open and monitor the same again
uses tlhelp32;
----
var Snap:THandle;
ProcessE:TProcessEntry32;
----
Snap:=CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
ProcessE.dwSize:=SizeOf(ProcessE);
if Process32First(Snap,ProcessE) then
begin \\Iterate through running processes
while Process32Next(Snap,ProcessE) do
\\Determine whether it's a child process of the saved PiD
if ProcessE.th32ParentProcessID = mySavedPiD then
\\ Creating the thread to monitor the process
cnThread:=TContinueThread.Create(ProcessE.th32ProcessID);
cnThread.Start;
\\ In the thread Execute
var hndl:THandle;
----
hndl:=OpenProcess(PROCESS_ALL_ACCESS ,False,PiD);
WaitForSingleObject(hndl, INFINITE);
It might not be the best solution but it works for me for now, however, still I need to handle the delta (processes which got finished during my program absence)
Creating a thread for each started process, wastes a thread. And the internal thread resources are limited. If you're using WaitForSingleObject(,INFINITE) now, take the time to learn about WaitForMultipleObjects and start a single thread to wait on a number of processes. (Or learn about jobs like #DavidHeffernan proposes)
I must process a very long database table an think of the most common way to abort this loop. The principal code sequence goes like this
procedure TForm.ProcessmyTable(Sender : TObject);
begin
.....
myTable.first;
repeat
ReadSingleRecordfromTable ( MyTable, aRecord) ;
ProcessMyRecord(aRecord) ;
MyTable.next;
until MYTable.EOF;
end;
unit .... ;
procedure ProcessMyRecord(aRecord : TMyDataRecord) ;
begin
// do not have user interface stuff here
// Application.Processmessages will not work here !!!
.... ( long running code sequence)
end;
Could do a timer and break the loop based on the timer with var as a flag support .... but is this really the most clever way of solving this issue?
If this code runs in the main thread, then you will need to service the message queue (i.e. call Application.ProcessMessages) if you want the user to interact with your program and abort. In which case I think you already know the solution. Call Application.ProcessMessages. If the user chooses to abort, set a boolean flag and check that flag regularly in the inner-most loop.
Of course, this is all rather messy. The fundamental problem is that you are performing long-running actions on the GUI thread. That's something you should not do. Move the database processing code onto a different thread. If the user chooses to abort, signal to the thread that it is to abort. For example a call to the Terminate method of the thread would be one way to do this.
When do you want to abort? If it takes too long of if the user says 'stop'?
In both cases change your
until MYTable.EOF;
to
until MYTable.EOF or Aborted;
then set your Aborted boolean either when the timer triggers or when the user presses a key (note that you then have to use Application.ProcessMessages in the loop for the program to be able to process the keypress). This will not abort in your processing routine but after each record. If that is not fast enough you will have to show your record processing routine.
If it's such a long process that the user might want to abort surely in a windows app there should be some interaction with the GUI, a count of records done or a progress bar (if not on every record then on a periodic basis) any call to update a label or progressbar will provide the opportunity to set an abort flag (so processmessages is not required). Plus if the user can see some progress they may be less likely to abort when bored but 95% complete.
IMHO :)
Is there a way to hook into the WndProc of a dbx user session?
Background:
dbx DataSnap uses Indy components for TCP communication. In its simplest form, a DataSnap server is an Indy TCP server accepting connections. When a connection is established, Indy creates a thread for that connection which handles all requests for that connection.
Each of these user connections consume resources. For a server with a couple hundred simultaneous connections, those resources can be expensive. Many of the resources could be pooled, but I don't want to always acquire and release a resource each time it is needed.
Instead, I'd like to implement a idle timer. After a thread finishes with a resource, the timer would start. If the thread accesses the resource before the timer has elapsed, the resource would still be "assigned" to that thread. But if the timer elapses before the next access, the resource would be released back to the pool. The next time the thread needs the resource, another resource would be acquired from the pool.
I haven't found a way to do this. I've tried using SetTimer but my timer callback never fires. I assume this is because Indy's WndProc for the thread isn't dispatching WM_TIMER. I have no control of the "execution loop" for this thread, so I can't easily check to see if an event has been signaled. In fact, none of my code for this thread executes unless the thread is handling a user request. And in fact, I'm wanting code to execute outside of any user request.
Solutions to the original question or suggestions for alternative approaches would be equally appreciated.
We tried to implement something to share resources across user threads using TCP connections (no HTTP transport, so no SessionManager), but ran into all sorts of problems. In the end we abandoned using individual user threads (set LifeCycle := TDSLifeCycle.Server) and created our own FResourcePool and FUserList (both TThreadList) in ServerContainerUnit. It only took 1 day to implement, and it works very well.
Here's a simplified version of what we did:
TResource = class
SomeResource: TSomeType;
UserCount: Integer;
LastSeen: TDateTime;
end;
When a user connects, we check FResourcePool for the TResource the user needs. If it exists, we increment the resource's UserCount property. When the user is done, we decrement the UserCount property and set LastSeen. We have a TTimer that fires every 60 seconds that frees any resource with a UserCount = 0 and LastSeen greater than 60 seconds.
The FUserList is very similar. If a user hasn't been seen for several hours, we assume that their connection was severed (because our client app does an auto-disconnect if the user has been idle for 90 minutes) so we programmatically disconnect the user on the server-side, which also decrements their use of each resource. Of course, this means that we had to create a session variable ourselves (e.g., CreateGUID();) and pass that to the client when they first connect. The client passes the session id back to the server with each request so we know which FUserList record is theirs. Although this is a drawback to not using user threads, it is easily managed.
James L maybe had nailed it. Since Indy thread does not have an message loop, you have to rely in another mechanism - like read-only thread-local properties (like UserCount and / or LastSeem in his' example) - and using main thread of the server to run a TTimer for liberating resources given some rule.
EDIT: another idea is create an common data structure (example below) which is updated each time an thread finishes its' job.
WARNING: coding from mind only... It may not compile... ;-)
Example:
TThreadStatus = (tsDoingMyJob, tsFinished);
TThreadStatusInfo = class
private
fTStatus : TThreadStatus;
fDTFinished : TDateTime;
procedure SetThreadStatus(value: TThreadStatus);
public
property ThreadStatus: TThreadStatus read fTStatus write SetStatus;
property FinishedTime: TDateTime read fDTFinished;
procedure FinishJob ;
procedure DoJob;
end
procedure TThreadStatusInfo.SetThreadStatus(value : TThreadStatus)
begin
fTStatus = value;
case fTStatus of
tsDoingMyJob :
fDTFinished = TDateTime(0);
tsFinished:
fDTFinished = Now;
end;
end;
procedure TThreadStatusInfo.FinishJob;
begin
ThreadStatus := tsFinished;
end;
procedure TThreadStatusInfo.DoJob;
begin
ThreadStatus := tsDoingMyJob;
end;
Put it in a list (any list class you like), and make sure each thread is associated
with a index in that list. Removing items from the list only when you won't use that
number of threads anymore (shrinking the list). Add an item when you create a new thread
(example, you have 4 threads and now you need an 5th, you create a new item on main thread).
Since each thread have an index on the list, you don't need to encapsulate this write (the
calls on T
on a TCriticalSection.
You can read this list without trouble, using an TTimer on main thread to inspect
the status of each thread. Since you have the time of each thread's finishing time
you can calculate timeouts.
We need to Start a thread into a service application we developed.
We did in the OnExecute event, and it failed, and later we did in the OnStart event, and it failed again. Maybe we have to do something else to start the thread.
The line of code we only have to type is MonitorThread.Start;
Where and how we can to start the thread??
Thanks.
On the face of it, starting a thread in a service is no different from starting a thread in any other kind of application. Simply instantiate the thread object and let it run. If you created the object in a suspended state, then call Start on it (or, in versions earlier than 2010, Resume).
MonitorThread := TMonitorThread.Create;
MonitorThread.Start; // or MonitorThread.Resume
If that doesn't work, then you need to take a closer look at exactly what doesn't work. Examine exception messages and return codes. Use the debugger to narrow things down.
If it's possible, I advise you to not create the thread suspended. Instead, just provide the object all the parameters it needs in its constructor. Let it initialize itself, and it will start running just before the constructor returns to the caller. No need for additional thread management outside the thread object.