200分,多个线程把搜集的数据各自生成txt文件,只启动一个线程添加到数据库,请指教?(200分)

  • 主题发起人 主题发起人 yecloudy
  • 开始时间 开始时间
Y

yecloudy

Unregistered / Unconfirmed
GUEST, unregistred user!
200分,多个线程把搜集的数据各自生成txt文件,只启动一个线程添加到数据库,请指教?
实现目的:
通过多线程把多个串口的数据添加到数据库。
实现模型:
1。启用多个线程(比如说a,b,c,d).
2.a,b,c,d各自搜集数据。把搜集的数据各自添加到
对应的txt文件。(a.txt,b.txt,c.txt,d.txt)
3。假使a搜集完成,通知另一个线程e,e就把a.txt文件添加到数据库。
4。同时,假如b也搜集完成,通知e,要等e添加a.txt完后,再来添加b.txt.
请问
1。e线程要怎么写。
2。线程a,b如何通知e,sendmessage只能用于window,有没有能通知启用线程的。
3。为了数据库不冲突,e同一个时刻只能添加某个文件的数据,所以怎么让
b必须等到e在添加完a.txt再添加b.txt.(a.txt,b.txt不是特定的,谁先搜集
完数据,就先。)
 
我觉得可以借助主线程。在主线程中维护一个列表。
当a、b、c搜集完数据时就往该列表中插数据。
而e就轮询该列表,一组一组地处理数据。
另外也可以考虑在主线程中完成e的功能啊。
 
呵呵,不用这么麻烦,你自己知道a。b,c,d,的文件名吧,你在e里面去检查文件,
或者固定的一个标志位,得到某个完成了,就执行添加,等添加完了,设置这个文件完成的标志
然后继续检查剩下的不就可以了么。
条条大路通罗马:)
 
在e中添加一插入函数如RequireInsert和一标志如Flag,但a,b,c之一完成时调用该函数,同时将标志置为某特殊状态
其它要求插入是如果该标志表示正在用,就放入缓冲队列中以备调用
 
同时添加可以用多个线程吗?不怕冲突吗?
 
请大家帮一下
 
做个变量Busy。
 
自己定义了一个缓冲数组(可以定义一个数据结构包括标志位和数据),收到数据后
马上标志一个可写的数组单元为正在写,把数据放到数组中,标志这个数组单元为可读,
后台一个线程不停的从头到尾扫描这个数组,如果有可读的单元,标志为正在读,然后
处理,放入数据库,处理完后标志为可写。继续扫描其他单元。
 
数据量大吗?我觉得你完全可以不要先放入文本文件,在放入数据库了。操作文件
速度比较慢的。至于自己定义的数据结构中还需要别的什么信息标志就看你的需要了,
比如可以加入收集的时间,哪个串口等。缓冲的大小也看需要了。我做的一个程序中
用了一个ini文件来配置这个缓冲数组的大小,以适应设备的多少。
 
可不可以不要e这条线程,a,b,c,d直接添加到数据库呢?
 
可以不要e线程的,但你需要在那几个线程中进行同步!
我在
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1237936
说明了如何用的方法,哎呀,我在这里顺便给你粘过来好了!
1、你先要在创建任何线程前定义并创建一个全局的互斥对象:
var
hMutex:THandle;
在程序的初始化部分创建该对象(在FormCreate或Initialization里都可以)
hMutex:=CreateMutex(nil,false,nil);
2、然后在你的线程体中将你需要保护的地方使用如下代码:
if WaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then
begin
//在此处添加你需要对数据库进行操作的代码
end;
//释放互斥对象,使其为发信号状态
ReleaseMutex(hMutex);
3、注意,别忘了在你的应用程序终止前用CloseHandle(hMutex)来删除该互斥对象,不然它将
在系统中一直存在(它是系统全局的对象);
这样,你就不怕你的多个线程冲突或出现“死锁”了:)
如果你给出代码,我也可以给你一个实际例子的,呵呵:)
 
to Heytommy,
请问1,临界区跟互斥对象有什么区别?
2。但a线程在对数据库进行添加时,请问别的线程在干什么?
200分是你的,努力啊
 
呵呵 ,,,
1:临界区和互斥的作用类似,都是用来进行同步的,但它们间有以下一点差别:
临界区只能在进程内使用,也就是说只能是进程内的线程间的同步;而互斥则还可用
在进程之间的;临界区所花消的时间很少,才10~15个时间片,而互斥需要400多个;
临界区随着进程的终止而终止,而互斥,如果你不用closehandle()的话,在进程
终止后仍然在系统内存在,也就是说它是系统全局对象;
2:当a在进行数据库的操作时,如果别的线程完成了采数,那么,它必须等到同步对象变
为发信号状态,也就是说要等a把工作作完了才能往数据库中加数据;
不知道这样的回答你还满意不?
 
to Heytommy
1.添加到数据库我用ADO,代码如下,请你看一下,好不好?
我想用ADODataSet的点updatacache,不过失败了。你知道为什么吗?
2。我想在a线程完成后,就send信息启动另一条线程f来添加数据,
不知到互斥对象能否用到,谢谢。
unit InsData;
interface
uses
Classes, ADODB,ActiveX,StrUtils,SysUtils;
type
TInsertDataThread = class(TThread)
private
{ Private declarations }
protected
ADODataSet: TADODataSet;
ADOCommand: TADOCommand;
ADOConnection: TADOConnection;
Ip,sName,Size,Time,DirName,TxtName:Ansistring;
F:TextFile;
procedure Execute;
override;
procedure AnalyzeDir(line:AnsiString);
procedure AnalyzeTxt(line:AnsiString);
public
constructor create(Sfilename:Ansistring);
Destructor Destroy;override;
end;

implementation
constructor TInsertDatathread.create(SFileName:AnsiString);
begin
inherited Create(true);
freeonterminate:=true;
CoInitialize(Nil);
ADOConnection := TADOConnection.Create( nil );
ADODataSet:= TADODataSet.Create(nil);
ADOCommand:=TADOCommand.Create(nil);
with AdoConnectiondo
begin
Provider := 'Provider=SQLOLEDB.1';
LoginPrompt := False;
KeepConnection := True;
ConnectionString := 'Provider=SQLOLEDB.1;Password=;Persist Security Info=True;User ID=;Initial Catalog=ftp;Data Source=';
connected:=True;
end;
{
with AdoDataSetdo
begin
Connection:=AdoConnection;
CacheSize:=1000;
locktype:=ltBatchOptimistic;
end;
}
with AdoCommanddo
begin
Connection:=AdoConnection;
prepared:=true;
end;
ip:=SFileName;
Resume;
end;

Destructor TInsertDataThread.Destroy;
begin
ADOCommand.Free;
ADOCommand:=nil;
ADOConnection.Free;
ADOConnection:=nil;
ADODataSet.Free;
ADODataSet:=nil;
CoUninitialize;
end;

procedure TInsertDataThread.Execute;
var
FileItem:string;
begin
DirName:=ip+'dir.txt';
txtName:=ip+'txt.txt';
if FIleExists(Dirname) then
begin
Assignfile(F,DirName);
Reset(F);
try
begin
while not Eof(f)do
begin
Readln(F,FileItem);
AnalyzeDir(FileItem);
with ADOCommanddo
begin
CommandText:='insert into allml(ip,name,time)'
+'values (:ip,:sname,:time)';
Parameters.ParamByName('ip').Value :=ip;
Parameters.ParamByName('sname').Value :=sname;
Parameters.ParamByName('time').Value :=time;
Execute;
end;
end;
end;
finally
closefile(f);
end;
end;
if FIleExists(txtname) then
begin
Assignfile(F,txtName);
Reset(F);
try
begin
while not Eof(f)do
begin
Readln(F,FileItem);
AnalyzeTxt(FileItem);
with ADOCommanddo
begin
CommandText:='insert into allfile(name,size,time,ip)'
+'values (:sname,:size,:time,:ip)';
Parameters.ParamByName('sname').Value :=sname;
Parameters.ParamByName('size').Value :=size;
Parameters.ParamByName('time').Value :=time;
Parameters.ParamByName('ip').Value :=ip;
Execute;
end;
end;
end;

finally
closefile(f);
end;
end;

// AdoDataSet.UpdateBatch(arall);
end;
 
to Heytommy
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1234793
能否就告书我你在这个帖子的一段代码?谢谢。
1。因为我不知道如何send消息给线程,我只会sendmessage到主窗口,
procedure Tmainform.ShowSearchSuccess(var msg:Tmessage);
begin

Ins:=TinsertDataThread.create(FtpIp);
end;
a完成后,就通知主窗口就启动添加到数据库的线程TinsertDataTHREAD,不过,在TinsertDataSet还在添加
数据的时候,又有新的线程b通知主窗口启动TINSERTDATATHREAD,所以就同时有两个
TinsertDataThread在运行,所以我该怎么该呢?谢谢。
下面是添加线程的代码,不过,有点问题。
unit InsData;
interface
uses
Classes, ADODB,ActiveX,StrUtils,SysUtils;
type
TInsertDataThread = class(TThread)
private
{ Private declarations }
protected
ADODataSet: TADODataSet;
ADOCommand: TADOCommand;
ADOConnection: TADOConnection;
Ip,sName,Size,Time,DirName,TxtName:Ansistring;
F:TextFile;
procedure Execute;
override;
procedure AnalyzeDir(line:AnsiString);
procedure AnalyzeTxt(line:AnsiString);
public
constructor create(Sfilename:Ansistring);
Destructor Destroy;override;
end;

implementation
constructor TInsertDatathread.create(SFileName:AnsiString);
begin
inherited Create(true);
freeonterminate:=true;
CoInitialize(Nil);
ADOConnection := TADOConnection.Create( nil );
ADODataSet:= TADODataSet.Create(nil);
ADOCommand:=TADOCommand.Create(nil);
with AdoConnectiondo
begin
Provider := 'Provider=SQLOLEDB.1';
LoginPrompt := False;
KeepConnection := True;
ConnectionString := 'Provider=SQLOLEDB.1;Password=;Persist Security Info=;User ID=;Initial Catalog=;Data Source=';
connected:=True;
end;

with AdoDataSetdo
begin
Connection:=AdoConnection;
CacheSize:=1000;
locktype:=ltBatchOptimistic;
end;
{
with AdoCommanddo
begin
Connection:=AdoConnection;
prepared:=true;
end;
}
ip:=SFileName;
Resume;
end;

Destructor TInsertDataThread.Destroy;
begin
ADOCommand.Free;
ADOCommand:=nil;
ADOConnection.Free;
ADOConnection:=nil;
ADODataSet.Free;
ADODataSet:=nil;
CoUninitialize;
end;

procedure TInsertDataThread.Execute;
var
FileItem:string;
begin
DirName:=ip+'dir.txt';
txtName:=ip+'txt.txt';
if FIleExists(Dirname) then
begin
Assignfile(F,DirName);
Reset(F);
ADODataSet.close;
ADODataSet.CommandText:='select * from allml where 0=1';
ADODataSet.open;//出错,‘标记没有储存’?
try
begin
while not Eof(f)do
begin
Readln(F,FileItem);
AnalyzeDir(FileItem);
with ADODataSetdo
begin
insert;
FieldByName('ip').asString:=ip;
FieldByName('name').asString:=sname;
FieldByName('time').asString:=time;
post;
end;
{
begin
CommandText:='insert into allml(ip,name,time)'
+'values (:ip,:sname,:time)';
Parameters.ParamByName('ip').Value :=ip;
Parameters.ParamByName('sname').Value :=sname;
Parameters.ParamByName('time').Value :=time;
// Execute;
end;
}
end;
AdoDataSet.UpdateBatch(arall);
end;
finally
closefile(f);
end;
end;
if FIleExists(txtname) then
begin
Assignfile(F,txtName);
Reset(F);
ADODataSet.close;
ADODataSet.CommandText:='select * from allfile where 0=1';
ADODataSet.open;
try
begin
while not Eof(f)do
begin
Readln(F,FileItem);
AnalyzeTxt(FileItem);
with ADODataSetdo
begin
insert;
FieldByName('name').asString:=sname;
FieldByName('size').asString:=size;
FieldByName('time').asString:=time;
FieldByName('ip').asString:=ip;
post;
end;
{
begin
CommandText:='insert into allfile(name,size,time,ip)'
+'values (:sname,:size,:time,:ip)';
Parameters.ParamByName('sname').Value :=sname;
Parameters.ParamByName('size').Value :=size;
Parameters.ParamByName('time').Value :=time;
Parameters.ParamByName('ip').Value :=ip;
// Execute;
end;
}
end;
end;

finally
closefile(f);
end;
end;

AdoDataSet.UpdateBatch(arall);
end;
 
哦,,那个帖子啊?我呆会再去帖,,,!
 
哦,,你的两段代码还真长:)
漫漫来!
 
先纠正你的线程实现体的部分问题!
TInsertDataThread线程的析构函数最好加上 Inherited Destroy;
构造函数最好加上FreeOnTerminate:=true;
必须 CoInitialize(Nil);
吗?它是用于初始化COM的吧?恩!?
我想用ADODataSet的点updatacache,不过失败了?什么意思?
你的:
CommandText:='insert into allml(ip,name,time)'
+'values (:ip,:sname,:time)';
中的 values 前缺了个空格吧?(我提这点是有原因的,我曾经遇到的问题就是缺这个空格
造成的,我加上后问题解决!)
对了,如果你想将返回值用ADODATASET来接收,你要用这样的语句:
ADODataSet1.Recordset := ADOCommand1.Execute;
否则,你的ADODataSet1里 是没有返回值的!
因为你给出了部分,,我也只能看到部分,,,如果原因不在这些了,那也可能是别的引起了,
这就要另当别论了哦!
 
我现在发现你的问题还真多,,,200分搞不定哦!!!
对于:
我想在a线程完成后,就send信息启动另一条线程f来添加数据,
不知到互斥对象能否用到?
如果你的线程是顺序的,,我的意思是你控制得到线程的执行顺序,那么线程就不会存在冲突,
就不用互斥了,你可以在a线程执行完了给主线程发送“完成”的消息,让主线程来启动f线程来
添加数据;如果你的a和f有可能在某段时间共存,也存在共同访问同一资源的risk,那么你就
需要用互斥了,,,也就是让a在添加数据的时候使f等着,到a完了,f才可以添加!!
 
线程一般要能进行消息响应,它自己必须有自己的消息循环,你发送消息的时候要用广播的
方式才行,,(你可以去SDK找相关的API),
你的消息处理是可行的,但一般不建议这样做,由主窗体来响应或主线程来响应要合适一些,
(主窗体其实可称为在主线程内的),
至于你说的:“在TinsertDataSet还在添加
数据的时候,又有新的线程b通知主窗口启动TINSERTDATATHREAD,所以就同时有两个
TinsertDataThread在运行”的问题,,你可以不用管这个消息,你 就让它发消息吧,
只不过你需要在用我说的线程的同步来解决这种冲突:在你的线程体里,通过检测互斥对象
来保护互斥代码,因为一个线程拥有一个互斥对象后,其它线程是不允许重复拥有它的,你可以
用WAITFORSINGLEOBJECT来等待前一个线程释放对它的拥有权,让另外一个线程来拥有以对需要
保护的互斥代码进行保护,,解决的办法我都给你写了好多次了,,,哎呀,,,你不是想要
我给你完整原代码吧???
 
后退
顶部