返回首页
当前位置: 主页 > 网络编程 > 其他实例教程 >

Using Semaphores in Delphi: The Connection Pool

时间:2011-12-15 01:44来源:知行网www.zhixing123.cn 编辑:麦田守望者

Semaphores are like mutexes on steroids. Not only do they provide for blocking thread synchronization, but they permit two or more threads, up to some specified maximum number, to work concurrently with a shared resource. As a result, they are unlike most other synchronization objects, which typically provide access to one thread at a time. For an introduction to the creation and use of semaphores, read the preceding article in this series on the Borland Developer Network site by clicking here.

This unique feature of a semaphore, the ability to provide two or more threads with simultaneous access to a resource, lends itself very well to the implementation of objects that contain a fixed number of resources that need to be made available in a multithreaded environment. Two common examples of objects of this type are thread pools and database connection pools. This article discusses the use of a semaphore to implement a connection pool.

Connection Pool Overview
A connection pool is an object designed to provide thread-safe access to a limited number of database connections in a multithreaded environment. In most scenarios, a connection pool contains one or more active database connections that can be used by any thread needing to work with the database.

A connection pool provides two primary benefits. The first is related to performance. Making and dropping a connection to a database is a relatively time consuming process. Depending on the environment, if each thread must make and then drop a connection each time data access is needed, a significant amount of processing power will be spent on the connection process. By comparison, a connection pool includes a fixed number of connections that can be shared among many threads. When a thread needs to work with a database, it obtains a handle to an existing connection that it uses temporarily. This reuse can dramatically reduce the number of times a connection is made and dropped, thereby producing an overall increase in performance.

The second benefit is related to connection counts. Many database licensing schemes permit only a limited number of simultaneous connections to the database. A connection pool, therefore, becomes a convenient mechanism for ensuring that no more than some fixed maximum number of connections can be active at a given moment. While a semaphore can be used outside a connection pool to manage the maximum number of simultaneous connections, a connection pool automatically provides this feature with the addition benefit of increased performance.

The FixedConnectionPool
The fixed connection pool unit, available for download from Code Central (by clicking here), provides an implementation of a connection pool. The purpose of this code is to demonstrate the use of a semaphore to provide multithreaded access to a limited resource (the connections in the pool). If you want to use this code in a production application, it is your responsibility to certify that the connection pool meets your application’s requirements. Note also, as of this writing, this connection pool has not been tested on a multiprocessor system.

There are four type declarations used in this connection pool. One is an interface and three are classes. The interface, named IConnection, defines the formal declaration of the connection pool interface, and also provides for the lifecycle management of individual connections.

The three classes consist of the connection pool object itself, named TFixedConnectionPool, as well as two helper classes. These helper classes are TConnectionModule, a data module descendant that is created once for each open connection, and TCleanupThread, a TThread descendant that drops connections that have not been used after some specified period of time.

IConnection
Let’s begin by considering the IConnection interface. This interface declaration is shown here:

IConnection = Interface(IInterface) //CHANGE //To use a connection of another type, change the //return type of the Connection function function Connection: TSQLConnection; function GetRefCount: Integer; function GetLastAccess: TDateTime; property LastAccess: TDateTime read GetLastAccess; property RefCount: Integer read GetRefCount;end;The Connection function returns a SQLConnection reference, which when implemented, refers to a SQLConnection object that is actively connected to a database. If you want to modify this connection pool to use a data access technology other than dbExpress, you need to change the return type of this Connection function to some other connection type, such as an TADOConnection (ADO), TIBDatabase (Interbase Express), or TSession (BDE).

The functions GetRefCount and GetLastAccess are the accessor methods for the RefCount and LastAccess properties, respectively. RefCount returns the number of current references to the IConnection implementing object. LastAccess returns the TDateTime of the last release of the IConnection implementing object. This value is used by the cleanup thread object to test whether the IConnection implementing object has gone unused for an extended period of time, and if so, to drop the unused connection.

TConnectionModule
The actual database connection is provided for by the TConnectionModule class. This class is a TDataModule descendant, and the connection component appears on this data module, as shown in the following figure.

 

TConnectionModule implements the IConnection interface. The SQLConnection that appears on this data module is the reference that is returned when the Connection method is invoked. As mentioned in the preceding discussion of the IConnection interface, if you want to use a connection other than dbExpress, you will replace this SQLConnection component with one that provides a connection using an alternative data access mechanism.

The following is the declaration of the TConnectionModule class. This class is commented extensively, and I am leaving these comments in this code segment for clarity.

//This data module provides the implementation//of the IConnection interface. To use a data access//mechanism other than dbExpress, modify the components//that appear on this data module, and change the class//of the Connection function in the IConnection interface//as well as in this class.TConnectionModule = class(TDataModule, IConnection) SQLConnection1: TSQLConnection;private { Private declarations }protected FRefCount: Integer; FLastAccess: TDateTime; //When the data module is created the //connection pool that creates the data module //will assign its critical section to this field. //The data module will use this critical section //to synchronize access to its reference count. CriticalSection: TCriticalSection; //This semaphore points to the FixedConnectionPool's //semaphore. It will be used to call ReleaseSemaphore //from the _Release method of the TDataModule. Semaphore: THandle; //These two static methods are reintroduced //in order to implement lifecycle management //for the interface of this object. //Normally, unlike normal COM objects, Delphi //TComponent descendants are not lifecycle managed //when used in interface references. function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; {IConnection methods} function GetLastAccess: TDateTime; function GetRefCount: Integer;public { Public declarations } {IConnection method} //CHANGE //To use a connection of another type, change the //return type of the Connection function function Connection: TSQLConnection;end;The Connection, GetLastAccess, and GetRefCount methods are implemented in this class to satisfy the implementation of the IConnection interface. The _AddRef and _Release static methods are reintroduced in this class to implement lifecycle management on the interface. This is necessary since the _AddRef and _Release methods introduced in TComponent (a TDataModule ancestor), do not implement lifecycle management through reference counting for VCL (visual component library) objects. This lifecycle management plays a critical role in the management of the connection pool.

------分隔线----------------------------
标签(Tag):delphi
------分隔线----------------------------
推荐内容
猜你感兴趣