Parallel Programming with OmniThreadLib

所需积分/C币:38 2018-05-26 14:13:58 4.27MB PDF
收藏 收藏

using locking(critical sections, spinlocks, TMonitor . )or interlocked operations, but they w slow the program down and they can introduce new problems(deadlocks) That is why I prefer data copying, communications and aggregation over data sharing Modern CPUs are fast and they can easily copy few tens or hundreds of bytes that are then sent to the thread so it can work on its own copy of the data and not on shared data. This approach is the basis of Omni ThreadLibrary and you' ll see it all through the book To write better code you should know which operations that are completely safe in single threaded world will get you in trouble when you are multithreading 1.1.1 Reading and writing shared data Let's start with a simple variable access. One thread is reading from a variable and another is writing to it 1 var 2345 2 a, b: integer 4 // thread 1 6a:=42 8//thread 2 9 o b This looks safe variable b will contain either 42 or previous data stored in a. Well, that is not entirely true b may also contain a mixture of both Depending on how the a is stored in memory(how it is aligned)the processor will access it either with one or two operations. If two operations are used, a read operation may partially overlap the write operation. For example, the code may read the first part of then a gets fully updated and only then the code reads the second part of This code behaves "as expected"(doesn' t cause problems)if the address of a gives remainder of o when divided by 4. We say that a is 4-aligned. Delphi in most cases makes all integers 4-aligned. Sadly, in some occasions, especially when structured types-classes and records- are nested variables are not well-aligned We say that the operation is atomic if it is performed in one step reads and writes of 4 aligned integers are atomic on Intel platform The simplest way to be sure that a value is correctly aligned is to use the TOmniAlignedInt32 record provided by the OmniThreadLibrary. It makes sure that the underlying data storage is correctly aligned and can as such be accessed atomically OmniThreadLibrary also implements TOmniAlignedInt64 type which creates 8-aligned int64 data This data may be accessed atomically only from 64-bit code Reads and writes of 8-aligned int64s are atomic only in 64-bit code TOmniAlignedInt64 implements atomic operations on int64s that can be used in 32-bit code 1.1.2 Modifying shared data Another example of typical code that doesn' t work correctly in multithreaded environment is modifying the same data from two threads In a typical program this data 第2页共213页 modification is hidden inside an operation that we think of as atomic while in reality it isn′t A standard example of this problem is implemented with two threads, one incrementing the shared value and other decrementing it 1 var 2 dala: integer 4 data : =0 6// thread 1 8 for i:=l to 100000 do 9 Inc(data) 10 11// thread 2 12 13 for I to 100000 do 14 Dec(data) In a single-threaded world, the value of data is o when this pseudo code finishes. In a multithreaded scenario, however it will lie somewhere between -100000 and 100000-and lat' s all we can say The problem with this code is that lnc and ec are not atomic operations rather they are implemented inside the CPU as a series of three operations-read data from memory increment (or decrement)data, and write data to memory One way to fix such code is to use already mentioned TOm iAligneuInt 32 which implements atomic Increment and Decrement operations 1 var 2 data: TOmnialigncdInt 0 6 thread l 8 for 1 to100000do 9 data increment 10 11// thread 2 r 1 to 100000 do 14 data Decrement Another option is to use interlocked operations from Delphi s System. Syncobjs unit var dla. lllteger' 3 4 data :=0 5 6// thread 1 8 for i:=1 to 100000 do 9 INterlocked Increment(data 10 thread b 13 for I to o0000 do 14 TInter locked Decrement(data) The third option is to protect increment/decrement operations by wrapping them in a 第3页共213页 critical section. You could, for example, use OmniThreadLibrary' STOmniCS 2 data: integer lock: TOnics 5 data: =0 6 7 // thread 1 8 9 for 1:I to 100000 do begin 0 lock Acquire 11 data Increment(data) 12 lock. Rolcasc 13 end 15// thread 2 6 7 for i: I to 100000 do begin 18 lock Acquire 19 data Decrement(data) 20 lock. Rclcasc 21 end Using interlocked operations is a bit slower than normal arithmetics and locking with critical sections is even slower. That' s one of the reasons I prefer to use data copying and aggregation The next example shows how the increment/decrement example could be rewritten with these principles in mind data: integer 5 var 6 tcmpData: integer 8 tempData:=0 9 for i:1 to 100000 do 10 Inc(LemmpDatad 12 send tempData to main thread 4 thread 2 15 var 16 tcmpData: integer 18 tempData: 0 19 for i:=I to 100000 do 20 Dec(tempData) 2 22 send tempData to main thread 24// main thread 26 data rcsult from thread 1+ rosult from thread 2 This approach doesn' t manipulate shared data which makes it run faster than interlocked and locking solutions. It does, however, require some communication mechanism that will send data to and from thread Different parts of this book will deal with that 1.1. 3 Writes masquerading as reads then execute some methods of that object in different threads we have to know exactl ny Another source of problems are shared objects. If we share an object between threads 第4页共213页 whether these operations are all thread-safe(that is, whether they can be executed in parallel from multiple threads) A simple example, which I saw in real code, shares a stream between two threads. The worker thread is reading from the stream and doing something with the data(it doesnt matter what). The main thread is monitoring the progress by tracking stream'sPositio and updating a progress bar on the user interface. In pseudocode, these two threads are executing following operations on a shared stream 1 var treat, 2345 // worker thread 6 data Read( 8// main thread 10 UpdatePosition(data Position/data Size) The problem here is easy to overlook as we percieve all operations on the shared stream as reading. In reality, this is not so. Let' s at them in more detail Read reads data from streams current position and then updates that current position Position just reads the current position Size is the worst of them all. Internally it is implemented as three Seek operations I Pos : Seek(0, coCurrent) 2 Result:= Seek(0. soEnd) 3 Seek(Pos, soBeginning) The problem here is that Sock modifies the current position. By calling Sizc in one thread we can change the current position just as the other thread starts reading from the stream That will cause wrong data to be read from the stream The morale here is simple. Sharing data between thread is always dangerous 第5页共213页 2018/524 2. Introduction to OmniThreadLibrary 2. Introduction to OmniThreadLibrary OmniThreadLibrary is a multithreading library for Delphi, written mostly by the author of this book (see Credits for full list of contributors). OmniThread Library can be roughly divided into three parts. Firstly, there are building blocks that can be used either with the OmniThreadLibrary threading helpers or with any other threading approach (f i. with Delphi s TThread or with AsyncCalls) Most of these building blocks are described in chapter Miscellaneous, while some parts are covered elsewhere in the book(lock-free Collections Blocking collection, Synchronization) Secondly, OmniThreadLibrary brings low-level multithreading framework, which can be thought of as a scaffolding that wraps the t thread class. This framework simplifies passim messages to and from the background threads, starting background tasks, using thread pools and more. In some ways it is similar to ITask which was introduced in Delphi XE7 except that Omni ThreadLibrary' s implementation offers more rounded feature set Thirdly, Omni ThreadLibrary introduces high-level multithreading concept. High-level framework contains multiple pre-packaged solutions(so-called abstractions)which can be used in your code. The idea is that the user should just choose appropriate abstraction (Future, Pipeline, Map.)and write the worker code, while the Omni ThreadLibrary provides the framework that implements the tricky multithreaded parts, takes care of synchronisation and handles other menial tasks 2.1 Requirements OmniThreadlibrary requires at least delphi 2007 and doesn ' t work with Free Pascal the reason for this is that most parts of omniThreadLibrary use language constructs that are not yet supported by the Free Pascal compiler High-level multithreading framework requires at least Delphi 2009. Delphi Xe or newer is recommended as some parts of the framwork aren t supported in Delphi 2009 and 2010 due to compiler bugs OmniThreadLibrary currently only works in Windows applications. Both 32-bit and 64-bit platform are supported. Applicatins can be compiled with the VCl library, as a service or as a console application. Fire Monkey is currently not supported 2.2 License OmniThreadLibrary is an open-sourced library with the Open BSD license This software is distributed under the bsd license Copyright (c)Primoz Gabrijelcic All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met o Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer Redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation 第6页共213页 2018/5/24 2. Introduction to OmniThreadLibrary and/or other materials provided with the distribution The name of the primoz Gabrijelcic may not be used to endorse or promote products derived from this software without specific prior written permission THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT LIMITED TO. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT INDIRECT INCIDENTAL SPECIAL EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES: LOSS OF USE DAtA, OR PROFITS: OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE In short this means that 1. You can use the library in any project, free, open source or commercial, without having to mention my name or the name of the library anywhere in your project, documentation or on the web site 2. You can change the source for your own use. You can also put a modified version on the web, but you must not remove my name or the license from the source code 3. I m not guilty if the software blows in your face. Remember, you got OmniThreadLibrary for free In case your company would like to get support contract for the OmniThreadLibrary, please contact me 2.3 Installlation 1. Download the last stable edition(download link is available at the OmniThread Library site), or download the latest state from the repository. Typically, it is safe to follow the repository trunk as only tested code is committed 2. If you have downloaded the last stable edition unpack it to a folder 3. Add the folder where you unpacked last stable edition/checked out the svn trunk to the Delphis Library path. Also add the src subfolder to the Library path. In case you are already using units from my GpDelphiUnits project, you can ignore the copies in the src folder and use gpdelphiUnits version 4. Add necessary units to the uscs statement and start using the library 2.3.1 Installing with GetIt Delphi/RAD Studio XE8 and newer come with an integrated package manager called GetIt With GetIt you can install OmniThreadLibrary with just a few clicks. Start Delphi and open Tools, GetIt Package Manager. Enter omnithreadlibrary' into the search bar. Then click on the INSTaLL button under the Omni ThreadLibrary graphics 第7页共213页 2018/524 2. Introduction to OmniThread Library @2 Gett Package Marager SEARCH O omnltnreaaiprary 9 FILTER ⊙A Omni. DX Thread . Free Libra o Purchased o Installed 》 SORT BY OmniThreadLibrary 3.07.1 Y CATEGORIES ⊙N INSTALL Y o Internet Of Things 54 Getit will download OmniThreadLibrary from Embarcadero s servers, add source path to the library path and compile and install the design package To find the demos, look at the Library path. It will contain something like this at the end S(BDSCatalogRepository)\OmniThreadLibrary_3. 07. 1-Tokyo(src\. To find the true path, look into Tools, Options, Environment Options, Environment Variables where BDSCaLalogRepository is defined Installed category and click the uninstall button under the omnithrea d librarys Removing OmniThreadLibrary from Delphi is equally simple. Just open GetIt, select graphIcs. 2.3.2 Installing with delphinus Delphinus is a 3 ra party package manager for delphi XE and newer, similar to Embarcadero s own GetIt package manager Unlike Getit, which comes integrated into Delphi, you have to install Delphinus manually Recommended installation procedure is 1. Stop delphi/RAd Studio 2. Install Delphinus with the web installer 1. It is recommended to right-click on the installer and select run as administrator. otherwise delphinus may not be able to create the installation folder 3. Start Delphi/RAD Studio 4.(Optional, but highly recommended)Open Tools, Delphinus, click the Settings icon and enter OAuth-Token. This will prevent frequent GitHub rate limitationerrors during operation. Instructions for generating the token can be found on the Delphinus wiki Once Delphinus is installed, click the Tools, Delphinus and in the Delphinus window click the green Refresh icon. When the package list is refreshed, enter omnithreadlibrary 第8页共213页 2018/524 2. Introduction to OmniThreadLibrary into the search bar and press <Enter>. Click on the Omni ThreadLibrary list item to get additional description in the panel on the right r Deutinus Psckdyer lar dyer Online(31) nse.clea A simplc and Updates A siTol and poehl m stirtreadting itrary tr Libra multithreading library for delphi Supports: Delphi 2CC7 to Tokyo Installed Platforms: Win32 Win64 License R5D-3-Cl3 Ise-Clear 心案 To install OmniThreadLibrary, click the Install icon(blue arrow pointing downwards to the disk drive). Be patient as Delphinus may take some time without displaying any progress on the screen When installation is complete, click the Show log button and in the log find the path where OmniThreadLibrary was installed (look for Adding libpathes message). Inside that folder you' ll also find all OmniThread Library demos K> You can find this path in Delphi s Library path configuration setting Delphinus will compile and install appropriate package so everything is set up for you Removing OmniThreadLibrary from Delphi is equally simple. Just open Delphinus, select the Installed category, select OmniThreadLibrary and click the remove icon(red circle with white X) 2.3.3 Installing design package OmniThreadLibrary includes one design-time component(TOmmiEventMonitor)which may be used to receive messages sent from the background tasks and to monitor thread creation/destruction. It is used in some of the demo applications If you installed Omni ThreadLibrary with Getit or Delphinus the installation process has already installed the design package and you may omit this step To compile and install the package containing this component, follow these steps From Delphi, open packages subfolder of the OmniThreadLibrary installation and select file OmniThread Library Packages. groupproj from the appropriate folder In the Project Manager window you ll find two projects OmniThreadLibraryRuntimefVER] bpl and OmniThreadLibrary Designtime VEr). bpl where VER) is package version- of your Delphi). If the Project Manager window is not visible, select View, Project Manager from the menu 第9页共213页

试读 127P Parallel Programming with OmniThreadLib
立即下载 低至0.43元/次 身份认证VIP会员低至7折
nikotin 不错,感谢楼主分享。
关注 私信
Parallel Programming with OmniThreadLib 38积分/C币 立即下载
Parallel Programming with OmniThreadLib第1页
Parallel Programming with OmniThreadLib第2页
Parallel Programming with OmniThreadLib第3页
Parallel Programming with OmniThreadLib第4页
Parallel Programming with OmniThreadLib第5页
Parallel Programming with OmniThreadLib第6页
Parallel Programming with OmniThreadLib第7页
Parallel Programming with OmniThreadLib第8页
Parallel Programming with OmniThreadLib第9页
Parallel Programming with OmniThreadLib第10页
Parallel Programming with OmniThreadLib第11页
Parallel Programming with OmniThreadLib第12页
Parallel Programming with OmniThreadLib第13页
Parallel Programming with OmniThreadLib第14页
Parallel Programming with OmniThreadLib第15页
Parallel Programming with OmniThreadLib第16页
Parallel Programming with OmniThreadLib第17页
Parallel Programming with OmniThreadLib第18页
Parallel Programming with OmniThreadLib第19页
Parallel Programming with OmniThreadLib第20页

试读结束, 可继续阅读

38积分/C币 立即下载 >