在线程里统计流水号老出错,请高手提个方案 (50分)

  • 主题发起人 主题发起人 8541051
  • 开始时间 开始时间
8

8541051

Unregistered / Unconfirmed
GUEST, unregistred user!
我在IdTCPServer的OnExecute事件中想实现这样的代码:
procedure TF_Main.IdTCPS1Execute(AThread: TIdPeerThread);
begin
1。监听客户端发来的信息;
2。读数据库中的最大流水号并且将流水号+1(流水号没有重复,且相邻记录差1);
3。将新的流水号及别的一些数据发给另一服务端;
4。接收到服务端的成功回执;
5。流水号入数据库成为最大流水号(没有成功回执流水号不能入库)
6。稍作处理将信息返回到客户端;
end;
问题出在2和5上。因为是自动多线程的。所以来一个线程就读一次流水号,流水号+1操作后入库。可能出现这种情况:一个线程从数据库中读出流水号,然后+1,还没来得及入库另一个线程就来了,读了和上一个线程一样的流水号,然后+1。这样入库会产生一样的流水号。所以请问大侠怎么能控制这样的线程。我记得是AThread.什么的属性可以。有别的方法也行。最好有一点代码说明。谢谢!
 
用数据库的计数器功能,+1操作应在数据库上完成。你用的是什么数据库?
 
用临界区把从度流水号到入库之间的操作保护起来,保证同一时刻只有一个线程在执行被保护的操作。
var
Lock1:TRTLCriticalSection;
procedure TF_Main.IdTCPS1Execute(AThread: TIdPeerThread);
begin
1。监听客户端发来的信息;
EnterCriticalSection(Lock1);
2。读数据库中的最大流水号并且将流水号+1(流水号没有重复,且相邻记录差1);
3。将新的流水号及别的一些数据发给另一服务端;
4。接收到服务端的成功回执;
5。流水号入数据库成为最大流水号(没有成功回执流水号不能入库)
LeaveCriticalSectionCriticalSection(Lock1);
6。稍作处理将信息返回到客户端;
end;
 
也可以用临时表保存可用的最大ID资源;
(ID,占用标志) 其中留第一条为特殊标志:
-1 ,0
ID=-1表示首条记录,其中0:表示此时资源表可用,1:表示无ID资源,某个进程正在生成新的资源
ID>-1的表示一个ID资源,如果 占用标志=0 表示可以引用,占用标志=1 表示正在被其他线程序占用
线程从临时表中获取最大GetMaxID,
(1)如果空而且-1记录的标志为0,则set标志为1;然后开始生成新的资源
(2)如果-1记录的标志为1,等待
(3)如果有ID>-1而且占用标志=0 的,set占用标志=1,并且引用删除,或者用完删除
.............
不成熟方法,供参考



 
一种简单不用加锁的同步方法:
var
FlowNo: Integer = 0; // 流水号

.....

thread中获取流水号方法:
var
n: Integer;
begin
n := InterLockedIncrement(FlowNo); // 获取当前流水号并且流水号加1
....
将n写到数据库时需要注意保证写入的数字比原字段的大,因为这里写数据库的语句可能比获取了后一个流水号的线程执行得晚,可以用例如如下的语句:
update set no=:n where id=xxx and :n>no

 
后退
顶部