多线程访问统一内存数据的问题???(100分)

  • 主题发起人 主题发起人 tp168
  • 开始时间 开始时间
T

tp168

Unregistered / Unconfirmed
GUEST, unregistred user!
我现正在编写一个程序,实现类似oicq的功能:
服务端程序中有一个动态数组UList,表示当前在线用户的信息,一个用户
同时只能登陆一次,如果后一个用户登陆时发现在在线用户信息表中
发现该用户ID,将发消息至前一用户让其退出(客户端程序有处理该消息)。
type
TUserInfo = record
code:string[5];
//用户ID
nick:string[12];
//呢称
ip:string[15];
port:integer;
status:char;
//状态
...
end
var
UList:array of TUserInfo;
我实现的具体思路是每接收到用户的一个请求,就建立线程在后台处理该
消息(因为这时有访问数据库的操作),同一时刻最多建立15个线程,后续
的客户请求放入消息队列中等待有空闲的线程可处理响应。
关键是用户请求登陆时我需遍历UList数组,查找该用户有没存在,如果不存
在,再遍历UList数组一次,查找UList.port=0的位置,如果找到,就选择
该位置记录该用户信息(问题1.如果不同的线程一起找到该位置该怎么办;问
题2.如果不同的线程找到不同的位置那不是在数组UList中,uin不是唯一键值)
如果没找到该位置,就SetLength(UList,Length(UList)+1)增加一维。
如果存在(假设该用户在UList的第i维找到),发送强制退出消息至UList.ip
、UList.port后,改变UList的内容(用当前登陆用户的信息改写,你们也
许会问如果前一个用户没收到怎么办,没关系,前一个用户就什么事也做不了,
因为服务器没有它登陆的在线信息)。用户请求退出时,我查找到UList中记录该
用户信息的位置,由于记录用户信息使用动态数组,数组做删除记录比较麻烦,
如果在中间删除,要移动它后面的数据,所以不做删除,只做如下操作:
UList.port:=0;UList.ip:='';(当UList中的port=0时表示该维可用来记录
后续登陆用户的信息)。
还有一个问题,我的程序中还有一个数组表示当前的活动线程:
CList:array of TEchoThread;(TEchoThread是程序中的响应线程)
i:=GetRestThread;(取得当前非活动线程位置)
CList:=TEchoThread.create(...);
function GetRestThread:byte;
var
i:integer;
begin
For i:=Low(CList) to High(CList)do
if CList已经关闭 then
begin
CList:=;
//置为非空闲状态
Result:=i;
Exit;
//CList已经关闭和置为非空闲状态该怎么写???
end;
Result:=0;
end;
望各位高手给于帮助,或给个思路在线程中该怎么同一访问、删除、增加动态数组
UList(不用Synchronize,我知道可以用临界区、互斥元,怎么用),多谢了。
 
这样做效率太低,
我建议你用完成端口来做服务器的I/O模型,具体的找《WINDOWS网络编程技术》一书,网上
http://www.csdn.net/Develop/article/11%5C11899.shtm有这个章节的例子。
 
保持同步,就用临界区了,效率要比其他几种方式(互斥元,信号量,事件)要高点
缺点就是不能跨进程使用
 
你好,张无忌,多谢你的帮助。
正如文章中所说的完成端口是用在当一个应用不得不同时处理大量的socket时,
我的服务程序不是要求时实性很强,我测试过了用我这个方法可以来的急处理
响应的。
 
或给个思路在线程中该怎么同一访问、删除、增加动态数组UList只有用临界区或者互斥之类
的办法,没有其他的办法了
 
你好,张无忌,在Delphi中具体怎么使用服务器的完成端口I/O模型???
在线程中怎么使用临界区???例如:
在主程序中->ulock:=TCriticalSection.create;
线程中->
procedure addlist(list:TUserInfo);
//用户登陆时增加用户至在线列表
var
i:integer;
begin
ulock.enter;
//锁定该数组
i:=Low(UList);
while i<=High(UList)do
//查找用户是否已经在线
begin
if UList.code=list.code then
Break;
i:=i+1;
end;
if i<=High(UList) then
//如果用户已经在线
begin
SendTo(UList.ip,UList.port,...,...) //发送强制退出消息至前一个登陆的用户
UList:=List;
end
else
begin
i:=Low(UList);
while i<=High(UList)do
//查找UList数组中port=0的位置
begin
if UList.port=0 then
Break;
i:=i+1;
end;
if i>High(UList) then
//如果没有找到port=0的位置
begin
i:=Length(UList)+1;
SetLength(UList,i);
end;
UList:=list;
end;
ulock.leave;
end;

procedure deluser(code1:string[5]);
//用户退出时在在线列表中删除该用户
var
i:integer;
begin
ulock.enter
i:=Low(UList);
IsFound:=False;
while i<=High(UList)do
begin
if UList.code=code1 then
Break;
i:=i+1;
end;
if i<=High(UList) then
//如果用户已经在线
begin
UList.port:=0;
UList.ip:='';
end;
ulock.leave;
end;
上面两个是线程的私有过程(我的线程是继承TThread生成的),线程中还有
多处访问(只访问)UList数组的地方是不是也要ulock.enter、ulock.leave,
如果在访问过程中要操作(经历较长时间),那其它线程不是都只能等待其完
成后才能操作UList数组???有没更好的办法???
 
var
CS:TRTLCriticalSection;
begin
InitializeCriticalSection(CS);
//开始初始化临界区
EnterCriticalSection(CS);
//进入临界区
在这个里面加入你要保护同步的资源,比如变量,全局链表等资源
LeaveCriticalSection(CS);
//离开临界区
DeleteCriticalSection(CS);
//关闭释放资源
end;
 
还有你如果在读的时候可以不用锁定链表,用一个状态变量来确定是否在读数据,如果在
读数据就不应该写数据,总之确定很麻烦,在计算机领域有个write/read模型,是操作系统
方面的难点,要根据你的具体内容来判断是否用临界区,比如你的一个一句读数据的代码
可以不用进入临界区,如果是2句连在一起,那就可能要进入临界区了,还有你对读出的数
据最好用变量来保存,在线程里用这个变量来处理。总之要灵活的运用临界区。
 
你好,张无忌,多谢你的帮助,
Delphi中已经封装了临界区TCriticalSection(也就是Api函数中的TRTLCriticalSection)
var
CS:TRTLCriticalSection;
//这个变量是不是应该定义成全局变量
begin
InitializeCriticalSection(CS);
//这句初始化临界区是不是也应该放在主程序
EnterCriticalSection(CS);
//进入临界区,等同于ulock.enter
在这个里面加入你要保护同步的资源,比如变量,全局链表等资源
LeaveCriticalSection(CS);
//离开临界区,等同于ulock.levae
DeleteCriticalSection(CS);
//关闭释放资源,是不是要放在主程序的Close事件中,否则达不到效果
//因为同一个TRTLCriticalSection对象不是只能同时被一个线程拥有,
//EnterCriticalSection(CS)将一直等待直到其它线程离开临界区???
end;
 
CS应该定义成全局变量,
释放资源应该放在线程的全部结束部分,初始化一般放在线程开始的部分,最好用一个启动线程
来管理所有的线程,在这个线程中用wait*****类的API函数处理,很方便,等所有的线程结束的
时候释放CS,开始的时候初始化CS。
TRTLCriticalSection可以被同一个进程所拥有的线程共享,所以可以达到你的要求。
 
EnterCriticalSection(CS)就是等待其他线程离开CS,离开后就锁定CS,直到你离开CS。
 
你好,张无忌,你是不是写错了,应该是进入后就锁定CS,直到你离开CS
 
EnterCriticalSection(CS)就是等待其他线程离开CS,离开后就锁定CS,直到你离开CS。
这句话的意思是EnterCriticalSection(CS)等待其他锁定CS的线程离开CS后就立刻锁定CS,
 
在执行对资源的使用,最后LeaveCriticalSection(CS)离开CS,提供给其他线程使用资源
 
接受答案了.
 
后退
顶部