Sign in Join
Wiki copytemporary

Manager Worker Threads System/fr: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Lazarus offre un accès aux librairies d'environnement multi-threaded de FPC sous Linux et Windows. If you are looking to develop lightning fast native engines specific to Linux or even Windows 64 this system is a great start to helping you understand how best to leverage multiple cores that modern scientific applications require to process vast amounts of data in real-time.
22
33This example is meant to get you thinking on how best to engineer a multi-threaded system that is re-entrant in nearly every aspect, as well as to demonstrate how to use Critical Sections to protect memory objects by synchronizing access to such objects.
44
55## Un gestionnaire de Thread
66
77Définissez ici autant de listes d'objets, de structures de données et de Sections critiques que de Threads nécessaires pour mettre votre système à niveau. Dans l'exemple fourni, la création d'une instance d'un gestionnaire de Thread nécessitera le facteur d'échelle souhaitée. Comme il s'agit juste d'un exemple simple, ce facteur d'échelle est statique mais avec de bons mécanismes de verrouillage ce système pourrait être mis à niveau pour caractériser une mise à l'échelle dynamique.
88
99## Une collection de Threads de travailleur
1010
1111Le gestionnaire de thread maintient une liste d'objets Thread qu'il "contrôle" et typiquement ne fait pas d'avantage pour interférer avec les opérations de chaque Thread de travailleur. La meilleure façon de conception hautement efficace de systèmes multi-threaded est de coder les thread de travailleur aussi serré que vous pouvez avec with as little critical sections as possible. And if you need to lock remember that all other threads at that instant in time **could** be placed in a wait state until that lock is released.
1212
1313## Critical Sections
1414
1515When protecting data from multiple threads from writing to data at the same place a Critical Section is needed. Critical Sections are supported and if you have any Windows Experience it is similar with a few caveats which are discussed in this article.
1616
1717[[doc:rtl/system/initcriticalsection.html|InitCriticalSection]](Lock : TRTLCriticalSection) - The name of this procedure is different from Windows API where the old name was InitializeCriticalSection. You must call this procedure because it is required for locks to perform.
1818
1919[[doc:rtl/system/donecriticalsection.html|DoneCriticalSection]](Lock : TRTLCriticalSection) - The name of this procedure is also different from Windows API where the old name was DeleteCriticalSection. You must call this procedure because it enables the Operating System to free memory it allocated to perform locking on your threads.
2020
2121[[doc:rtl/system/entercriticalsection.html|EnterCriticalSection]](Lock: TRTLCriticalSection) - The name of this procedure is identical to Windows API. You must think carefully where you place these and you always follow this up with an exception handling block.
2222
2323[[doc:rtl/system/leavecriticalsection.html|LeaveCriticalSection]](Lock: TRTLCriticalSection) - The name of this procedure is identical to Windows API. You must ensure that this procedure is called finally in your Locking/Unlocking block. There is one exception to this rule but you really need to keep track of locks. In the event that a method can take long periods of time it is conceivable that you would unlock the thread, if you know that an operation is going to take a significant amount of time, and re-lock it again. In that event, just make sure you handle all exceptions so that the Lock is eventually unlocked.
2424
25-` Example Block that Performs Locking and Unlocking`\
26-`   EnterCriticalSection(Lock);`\
27-`   Try`\
28-`     // Perform Code here`\
29-`   Finally`\
30-`     LeaveCritialSection(Lock);`\
31-`   end;`
25+``` pascal
26+ Example Block that Performs Locking and Unlocking
27+ EnterCriticalSection(Lock);
28+ Try
29+ // Perform Code here
30+ Finally
31+ LeaveCritialSection(Lock);
32+ end;
33+```
3234
3335## Putting Threads To Sleep
3436
3537Under Windows, making a thread go to sleep is best accomplished **not** by the **Sleep** method, rather the **WaitForSingleObject** method. Waiting for an event places threads in a stasis where there is little to no CPU cycles being used by the system until such time as an event was signaled or the specified timeout has been reached.
3638
3739Since FPC did not offer a WaitForSingleObject method, the best way to achieve highly efficient systems is to use Event driven Waits. Even though you know that no event will trigger an interrupt to that wait, it is best to use an Event. Therefore, in the example included, instead of using a Sleep(WAIT_MILLISECONDS) I included a technique which creates one Event Handle per Manager. Keep in mind most Lazarus applications, most likely will include only one instance of a Manager, but these exemplary units can be used in applications that contain multiple instances of the Manager.
3840
3941## Adding Data
4042
4143When adding data to the system, keep in mind that memory is required for each data object for the duration of its cycle. In the example included, there is a data structure defined and represents a file that exists on a network or on the local machine. This system takes input as data objects, queues them, and processes them.
4244
4345For other data objects, this project can be extended to use a thread-pooled SQL connector and issue SQL statements to retrieve data to process and even callbacks to store processed data objects after worker threads processed them.
4446
4547## Push Data In
4648
4749First, data is converted to a structure and added to a collection of items to be added to the queue. Organized this way, the locking only occurs if you have multiple threads trying to push data into the system.
4850
4951This is highly efficient in many ways. Take adding data from the main application thread for one example: Locking never occurs. This is accomplished because only the main application thread will ever get a chance to add items. Take adding data from another multi-threaded instance example: locking only occurs to the instance thread that is trying to add data to the queue. So under both scenarios, ALL Worker threads are not put into a sleep mode while data is being added to the system.
5052
5153## Propagate Data to the Queue
5254
5355Before data even reaches any one individual worker thread it must be queued. The manager is maintaining which items have been added, queued, and finally processed. The worker threads are only requesting more data to process. Data propagates to the queue in controlled fashion by way of a Process method inside the Manager thread's execution.
5456
5557## Data inside the Queue
5658
5759Data resides in the queue until a worker thread requests a Data Object. Having established a lock, no other worker threads can be assigned data until their lock as been established. The first Data object is pulled from the Queue list, removed from the Queue list, added to the Processing list, where it will wait until the next call to get more data will occur. This is highly efficient because it serves two purposes in one call by Placing the data objects in their appropriate list, as well as feeding new data to a particular worker thread. Items added to the system are processed in a First In, First Out (FIFO) method because items added first will be the first to be processed.
5860
5961**Note:** FILO would have been better if I were using a TThreadDataPointers rather than a TList object. The reason is because TList.First and SetLength(). I would be pivoting off the Last Element in the TThreadDataPointers and using SetLength(Length-1) to reclaim memory space. These are things you will need to consider when designing your system.
6062
6163## Processing Data
6264
6365The concept of processing data from a Worker Thread standpoint will be the most critical piece of code you will write. Every declaration is going to cost cycles. If you can, declare variables local to the thread object and let them be, Declaring variables inside the process method is going to be at too high a cost however, processing does need to happen here so just think twice.
6466
6567- Introduce NO waits here.
6668- Use Exception Handlers here or it will disrupt the processing engine.
6769- Be right to the point with your code. Try to optimize everything. The execution of code can be slow and costly and will hamper the number of simultaneous threads your system can allocate if you are sloppy.
6870
6971Declare variables local to the thread object as private and deallocate them at the Destruction event of the Worker Thread. It would be costly to keep allocating and deallocating memory during the Process method or any methods you add to process a single data object.
7072
7173**Note:** A single data object can be much more than a string. You could make these an NxM matrix of In64s or Floats or what ever you need.
7274
7375## Processed Data
7476
7577This example pushes Processed data during the GetNextItem call to the Manager. This was done because there was an efficiency gain to lock the list at that point and move data where it belongs all at the same time. Your needs may differ however, think about how you want to organize your data before actually committing to the way in which to implement.
7678
7779This example does not include a callback to notify the main application that a data object has just been completed. It is something that may or may not be required since merely adding a file to this system would pretty much guarantee it was processed.
7880
7981Which leads us into logging, while entirely another matter, is useful. I have experience with Windows and TFileStream being thread safe but that is *Windows*. Under unix, I would probably stick to adding a custom log file using TFileStream rather than posting data to any system log. The reason is because these simultaneous systems can create tens of thousands of log entries per second if done properly, and most system administrators won't appreciate cleaning out log files on your behalf.
8082
8183## Fichiers unité
8284
8385L'exemple complet peut être téléchargé à partir de l'adresse [Lazarus CCR](https://sourceforge.net/project/showfiles.php?group_id=92177&package_id=148359&release_id=648747) sur SourceForge.
8486
8587Voir aussi [[Parallel procedures/fr|Procédures parallèles]].
8688
8789---
8890*From the Free Pascal wiki, page "Manager Worker Threads System/fr", as it stood on 2017-12-15 after a change by Visithierry, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history