标签:end delphi AProc FSyncRecList 访问 第七节 线程 数据库
转载自:https://www.cnblogs.com/lackey/p/6337357.html
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQuery ,DataSoure, DbGrid 等,就可以实现数据库的访问操作。 这种方式,可以理解为在主线程时空中访问数据库。 如果某一个查询或更新操作耗时较长,那么,界面将会假死。 1.在线程时空中访问数据库 其实,上文中提到的这个 AdoConnection 不单只能在主线程时空中访问, 亦可以在另一个多线程时空里访问。但有一个重要的前提: 即:任意时刻,只能是一个线程访问 AdoConnection ! 可以是多线程时空访问,也可以是主线程时空访问,它们可以交替访问,但不能同时访问。 故此,我们可以定义一个 DataThread 线程时空,把其它线程时空中需要访问数据库的操作, 全部塞入到 DataThread 时空中。具体做法是在 DataThread 中设计一个接口,如下:unit uJooThread; interface uses Classes, uFooThread; type TJooThread = class(TFooThread) public procedure Synchronize(AProc: TThreadMethod); end; implementation { TJooThread } procedure TJooThread.Synchronize(AProc: TThreadMethod); begin ExecProcInThread(AProc); // 再设计一个等待 AProc 执行结果功能。 end; end.
这样既简化了其它线程访问数据库的操作,也避免了因为数据库操作耗时引起界面假死。 另外,如果访问数据库发生了异常,重新 Create AdoConnection 然后再连接的操作也在这一个线程中进行, 就不必考虑数据库操作的先后问题。如:不会出现需要访问数据库时, AoConnection 是损坏状态的情况。 也就是说,用这个线程,把访问数据库的操作进行了排队。 定义一个工作线程A, 先从数据库中取参数,再进行计算,然后把结果再更新到数据库。 如果有10个线程A实例,那么线程A访问数据库的时候,只需要把访问操作塞进 DataThread 中即可。 有朋友肯定会有疑问,为何不为每一个线程指定一个 AdoConnection 。这样编程将会变得简单。 一、数据库的连接是会消耗资源的,连接数是有上限的。 二、如果每个线程的 AdoConnection 产生的操作都是访问同一个表。 那么数据库自身会上锁,将它们变成串行执行,并不能提高效率。 2.多个客户端,同时从数据库取参数会如何? 假设每个客户端通过一个 AdoStoredProcduce (存储过程)来获取参数,我们可以在此存储过程中, 加入数据库的 sp_getapplock (以 MSSQL为例)来让客户端按顺序获取到参数。更新亦同理。 由此可见,学习了多线程的锁,亦能推而广之理解数据库的锁。 以下是详细代码,至此,本教程的任务基本完成。 本例的调用方法就不写了。如果你读懂了所有的教程,应该会写了。 如果没读懂,写了又有什么意义呢?请恶补面向对象的基础知识。 以后的其它教程,均以本多线程教程为基础。
unit uJooThread; interface uses Classes, SyncObjs, uFooThread, uFooList; type PSyncRec = ^TSyncRec; TSyncRec = record Method: TThreadMethod; // 这是类的方法 Proc: TThreadProcedure; // 这是匿名方法 // 本例只写了类的方法。需要匿名方法,请自行重载 Sync 与 Queue Signle: TEvent; Queue: boolean; end; TSyncRecList = class(TFooList<PSyncRec>) //用于装执行代码的 List protected procedure FreeItem(Item: PSyncRec); override; end; TJooThread = class(TFooThread) private FSyncRecList: TSyncRecList; procedure Check; public constructor Create(ACanAccessCom: boolean); destructor Destroy; override; procedure Synchronize(AProc: TThreadMethod); // 阻塞到 AProc执行完毕才返回。 procedure Queue(AProc: TThreadMethod); // 塞入线程后立即返回。 end; // 本例就是前面单节讲的知识的综合运用。 // TEvent,FooThread,FooList,全都用上了。 // 并构建了一个新的线程功能。 // 当我写完以后发现,与系统源码中, // 窗口接收 WM_NULL 消息后的处理UI操作的功能,几乎是一模一样的。 // 不同的是,本例是在线程时空,系统源码是在主线程时空。 implementation { TJooThread } procedure TJooThread.Check; var p: PSyncRec; begin FSyncRecList.Lock; // 所有要执行的代码,都在这个 List 中了。 // 此处是线程时空,故从List 中取出并执行代码即可。 try p := nil; if FSyncRecList.Count > 0 then // 每次取 List 的第一个来执行。 begin p := FSyncRecList[0]; FSyncRecList.Delete(0); end; finally FSyncRecList.Unlock; end; if Assigned(p) then begin if Assigned(p.Method) then p.Method else if Assigned(p.Proc) then p.Proc(); if not p.Queue then // 如果是阻塞,就置信号。 p.Signle.SetEvent; Dispose(p); ExecProcInThread(Check); end; end; constructor TJooThread.Create(ACanAccessCom: boolean); begin inherited; FSyncRecList := TSyncRecList.Create; end; destructor TJooThread.Destroy; begin FSyncRecList.Free; inherited; end; procedure TJooThread.Queue(AProc: TThreadMethod); var p: PSyncRec; begin FSyncRecList.Lock; try new(p); FSyncRecList.Add(p); p.Method := AProc; p.Queue := true; ExecProcInThread(Check); finally FSyncRecList.Unlock; end; end; procedure TJooThread.Synchronize(AProc: TThreadMethod); var p: PSyncRec; o: TEvent; begin FSyncRecList.Lock; try new(p); FSyncRecList.Add(p); p.Method := AProc; o := TEvent.Create(nil, true, false, ''); p.Signle := o; p.Queue := false; ExecProcInThread(Check); //触发线程启动 finally FSyncRecList.Unlock; end; o.WaitFor; // 等待 AProc 执行完毕的信号 o.Free; end; { TSyncRecList } procedure TSyncRecList.FreeItem(Item: PSyncRec); begin inherited; if Assigned(Item.Signle) then Item.Signle.Free; Dispose(Item); end; end.
标签:end,delphi,AProc,FSyncRecList,访问,第七节,线程,数据库 来源: https://www.cnblogs.com/approx/p/11852351.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。