Tqueue和流的问题(50分)

  • 主题发起人 主题发起人 midastime
  • 开始时间 开始时间
M

midastime

Unregistered / Unconfirmed
GUEST, unregistred user!
var
MyQueue:TQueue

stream1: TMemoryStream;
begin
stream1:=TMemoryStream.Create;
stream1.Write(s,sizeof(s)) ;
new(astream);
stream1.Position:=0;
myqueue.Push(stream1);
问题在于,我的stream1在pop前值更改,pop出的数据也会发生更改。
怎么才能使队列中的数据跟stream1以后的改变无关呢?〉
 
因为你改动的是同一块内存区域
队列只是帮你维护这些内存区域的一种连接方式
要使队列的中的数据和原始数据无关,你要将每个结点从原始数据那儿做一份拷贝再压入队列
 
52free大侠,一直盼着您呢。我也想这样啊。不过,我不知道怎么做啊。我新建一个stream组行吗?下标用myqueue.count。可是我不知道怎么下手,我学delphi刚3个多月。大侠能帮忙举个例子说明怎么管理这块内存区域吗?或者怎么完成一个完善点的队列,看过你03年这方面的帖子哦,一直盼着您的,大侠。
指导一下小弟了。
 
你的这个需求我觉得莫名其妙,这有什么意义??

随便写了个例子哦,因为这样的话你需要有另一个队列或栈维护另一组内存块,否则你怎么free那些你create出来的内存区域呢?


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Contnrs;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
MyQueue:TQueue;
stream1, stream2: TMemoryStream;


implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin
MyQueue := TQueue.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
s , s1: String;
begin
s := '大富翁' ;
s1 := 'DFW';
stream1:=TMemoryStream.Create;
stream1.Write(s, sizeof(s)) ;
stream1.Position:=0;
stream2 := TmemoryStream.Create;
stream2.CopyFrom(stream1, stream1.Size);
stream2.Position := 0;
myqueue.Push(stream2);
stream1.Clear;
stream1.Write(s1, sizeof(s1)) ;
stream1.Position:=0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
while MyQueue.Count <> 0 do
begin
TMemoryStream(MyQueue.Pop).Free;
end;

MyQueue.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
S: String;
begin
TMemoryStream(MyQueue.Pop).Read(S, 20);
caption := s;
end;

end.
 
多谢大侠哦,我想写个程序实践一下,多个线程不断接收数据,将这些数据写入缓冲区,然后一个线程读出去。stream1会加入队列后会free,接收新的数据,再压入,如果不新开一片内存的,新的数据会冲掉以前压入的数据。所以我想新开一片区域存储。可是我不知道新开的这片区域该怎么管理啊?
比如使用stream2新开的区域,那下一个来得数据还保存到stream2中是不是还会造成影响,但是如果使用数组的话。下标如何设置呢?
 
var
s:string;
astr:^string;


new(astr);
s:='ddd';
astr^:=s;
myqueue.Push(astr);
new(astr);
s:='69';
astr^:=s;
myqueue.Push(astr);
为什么我用astr队列操作字符串时,源数据S的改变对队列的数据没有影响?流是否也能达到相应的效果呢?
大侠帮帮忙啊。
 
因为astr已经又被你new过一次了!
从你上面这段程序看在队列中压入了两个指针地址,它们分别指向两块不同的内存区域
跟你上面的流的说法根本是两回事,建议你找本C语法的书(pascal的不好找)好好看一看指针的那一部分
 
用磁盘队列做了,stream和Tqueue是在搞不懂了。只好换东西完成。52free大侠,多谢。俺水平差了点,以后还要你多照顾啊。


const divaccount = 100;
type
TcommQueue = class(Tcomponent)
private
FFilename: string

Ffilesize: longint

Ffrontpointer, Frearpointer: longint

Fscroll: char
//是否回绕
hMutex: THandle
//互斥句柄
Q: file;
published
property Filename: string read FFilename write Ffilename;
property filesize: longint read FFilesize write Ffilesize;
property frontpointer: longint read Ffrontpointer write Ffrontpointer;
property rearpointer: longint read Frearpointer write Frearpointer;
private
function getleftsize(var leftsize: integer): integer;
function readheadfront: integer;
function readheadrear: integer;
function readFileSize: integer;
function readscroll: integer;
function writeheadfront(const frontposition: longint): integer;
function writeheadrear(const rearposition: longint): integer;
function writescroll(const myscroll: char): integer;

//写入对应的一条队列的大小;
function writebuffersize(const position: longint
const buffersize: longint): integer;

//从磁盘文件读出队列,保存为流
function readStream(var aStream: TMemoryStream): integer;
//将流写入磁盘队列
function writeStream(aStream: TMemoryStream): integer;

// 加一处理
function addone(var position: longint): longint;

public
//打开磁盘文件;
function Open(const Myfilename: string
const MyFileSize: longint): integer;
//关闭队列
procedure close;
//判断磁盘队列是否为空;1代表True ,0代表假
function empty: integer;
//读取磁盘队列一条内容
function readQueue(var buffer
var size: longint): integer;
//向磁盘队列插入一条内容
function writequeue(const buffer
const size: integer): integer;
//读入对应的一条队列的大小;
function readbuffersize(const position: longint
var buffsize: longint): longint;

end;
implementation

//根据磁盘名得到磁盘的对应磁盘号
function GetDriveBytebyName(Filename: string): byte;
var
xdrive: string;
xdrivechar: char;
xdrivebyte: byte;
begin
if length(filename) > 0 then
begin
xdrive := copy(filename, 1, 1);
xdrive := uppercase(xdrive);
xdrivechar := xdrive[1];
xdrivebyte := ord('A');
result := (ord(xdrivechar) - xdrivebyte) + 1;
end;
end;

//打开磁盘文件,并初始化文件
function TcommQueue.open(const Myfilename: string
const MyFileSize: longint): integer;
{---------
返回值为-1 打开文件出错或写出错
-3 磁盘空间不足
-4 文件只读
}
var
buffer: array[0..511] of char;
writeaccount: integer;
i: integer;
drive: byte;
diskfreesize: int64;
xx: string;
xxx: char;
begin
FFilename := MyFilename;
FFileSize := MyFileSize;
result := 1;
Assignfile(Q, FFilename);
//如果文件存在,打开
if fileexists(FFilename) then
begin
if fileisreadonly(Ffilename) then
begin
result := -4
//文件为只读
exit;
end;
try
Reset(Q, 1);
//从磁盘队列读取磁盘队列的头、尾指针、文件大小、是否回绕。
readheadfront;
readheadrear;
readFileSize;
readscroll;
except
result := -1
//代表打开文件错误
end;
end
else
//不存在,创建
begin
try
//判断磁盘队列
drive := getDriveByteByName(Ffilename);
diskfreesize := diskfree(drive);
if diskfreesize <= FFileSize then
begin
result := -3
//磁盘空间不足
exit;
end;
//初始化队列
Ffrontpointer := 512;
Frearpointer := 512;
Fscroll := 'N';
buffer[0] := 'A';
buffer[1] := 'A';
move(Ffrontpointer, buffer[2], 4);
move(Frearpointer, buffer[6], 4);
move(FFileSize, buffer[10], 4);
buffer[14] := 'N';
fillchar(buffer[15], 497, '0');
rewrite(Q, 1);
blockwrite(Q, buffer, 512, writeaccount);
if writeaccount <> 512 then
begin
result := -1
//代表写入数据有误
exit;
end;
for i := 1 to FFileSize div 512 do
begin
fillchar(buffer[0], 512, '0');
blockwrite(Q, buffer, 512, writeaccount);
if writeaccount <> 512 then
begin
result := -1
//代表写入数据有误
exit;
end;
end;
fillchar(buffer[0], FFileSize mod 512, '0');
blockwrite(Q, buffer, FFileSize mod 512, writeaccount);
if writeaccount <> FFileSize mod 512 then
begin
result := -1
//代表写入数据有误
end;
except
result := -1;
end;
reset(Q, 1);
end;
//创建互斥句柄
hMutex := CreateMutex(nil, false, nil);
end;

//关闭队列
procedure TcommQueue.close;
begin
closefile(Q);
closeHandle(hMutex);
end;

//判断磁盘队列是否为空
function TcommQueue.empty: integer;
begin
result := 0;
if Fscroll = 'N' then
begin
if Frearpointer = Ffrontpointer then
result := 1
else
result := 0;
end;
end;

//获取磁盘文件所剩空间;
function TcommQueue.getleftsize(var leftsize: longint): integer;
begin
if Fscroll = 'N' then
begin
leftsize := (FFileSize - Frearpointer) + (Ffrontpointer - 512);
end
else
begin
leftsize := Ffrontpointer - frearpointer;
end;
end;

//读取头指针
function TcommQueue.readheadfront: integer;
var
readaccount: integer;
buffer: array[0..3] of char;
begin
//移动磁盘文件指针到2的位置
seek(Q, 2);
blockread(Q, buffer, 4, readaccount);
move(buffer[0], Ffrontpointer, 4);
if readaccount <> 4 then
result := 0
else
result := 1
end;

//读取尾指针
function TcommQueue.readheadrear: integer;
var
readaccount: integer;
buffer: array[0..3] of char;
begin
seek(Q, 6);
blockread(Q, buffer, 4, readaccount);
move(buffer[0], Frearpointer, 4);
if readaccount <> 4 then
result := 0
else
result := 1
end;

//读取文件指定的最大尺寸;
function TcommQueue.readFileSize: integer;
var
readaccount: integer;
buffer: array[0..3] of char;
begin
seek(Q, 10);
blockread(Q, buffer, 4, readaccount);
move(buffer[0], FFileSize, 4);
if readaccount <> 4 then
result := 0
else
result := 1
end;

//写入头指针
function TcommQueue.writeheadfront(const frontposition: longint): integer;
var
buffer: array[0..3] of char;
writeaccount: integer;
begin
move(frontposition, buffer[0], 4);
seek(Q, 2);
blockwrite(Q, buffer, 4, writeaccount);
if writeaccount <> 4 then
begin
result := -1;
exit;
end
else
result := 1;
Ffrontpointer := frontposition;
end;

//写入尾指针
function TcommQueue.writeheadrear(const rearposition: longint): integer;
var
buffer: array[0..3] of char;
writeaccount: integer;
begin
move(rearposition, buffer[0], 4);
seek(Q, 6);
blockwrite(Q, buffer, 4, writeaccount);
if writeaccount <> 4 then
begin
result := -1;
exit;
end
else
result := 1;
Frearpointer := rearposition;
end;

//读取对应的一条队列的大小;
function TcommQueue.readbuffersize(const position: longint
var buffsize: longint): longint;
var
buffer: array[0..3] of char;
I: integer;
readaccount: integer;
begin
result := 1;
seek(Q, position);
//判断剩余大小是否大于4,如果小于4,则得分开读
if FFileSize - position < 4 then
begin
for i := 0 to (FFileSize - position - 1) do
begin
blockread(Q, buffer, 1, readaccount);
if readaccount <> 1 then
begin
result := -1;
exit;
end;
end;
seek(Q, 512);
for i := (FFileSize - position) to 3 do
begin
blockread(Q, buffer, 1, readaccount);
if readaccount <> 1 then
begin
result := -1;
exit;
end;
end;
end
else
begin
seek(Q, position);
blockread(Q, buffer, 4, readaccount);
if readaccount <> 4 then
begin
result := -1;
exit;
end;
end;
move(buffer[0], buffsize, 4);
end;

//写入对应的一条队列的大小;
function TcommQueue.writebuffersize(const position: longint
const buffersize: longint): integer;
var
buffer: array[0..3] of char;
I: integer;
writeaccount: longint;
begin
result := -1;
seek(Q, position);
move(buffersize, buffer[0], 4);
//判断剩余大小是否大于4,如果小于4,则得分开写
if FFileSize - Frearpointer < 4 then
begin
for i := 0 to (FFileSize - Frearpointer - 1) do
begin
blockwrite(Q, buffer, 1, writeaccount);
if writeaccount <> 1 then
begin
result := -1;
exit;
end;
end;
seek(Q, 512);
for i := (FFileSize - Frearpointer) to 3 do
begin
blockwrite(Q, buffer, 1, writeaccount);
if writeaccount <> 1 then
begin
result := -1;
exit;
end;
end;
end
else
begin
blockwrite(Q, buffer, 4, writeaccount);
if writeaccount <> 4 then
begin
result := -1;
exit;
end;
end;
end;

//读取是否回绕字符值
function TcommQueue.readscroll: integer
//读取是否回绕字符值
var
readaccount: integer;
begin
result := 1;
seek(Q, 14);
blockread(Q, Fscroll, 1, readaccount);
if readaccount <> 1 then
result := -1;
end;

//写入是否回绕字符值
function TcommQueue.writescroll(const Myscroll: char): integer;
var
writeaccount: integer;
begin
result := 1;
seek(Q, 14);
blockwrite(Q, myscroll, 1, writeaccount);
if writeaccount <> 1 then
begin
result := -1;
exit;
end;
Fscroll := Myscroll;
end;

//从磁盘文件读出队列,保存为流
function TCommQueue.readStream(var aStream: TMemoryStream): integer;
var
buffer: array[1..divAccount] of char;
i: integer;
ActReadNum: Longint;
aleft: Longint;
bufferSize: longint;
begin
result := 1;
//进入互斥,阻止其他线程访问
if waitForSingleObject(hMutex, INFINITE) = WAIT_OBJECT_0 then
begin
try
//判断底部剩余空间是否大于4,以判断是否分开读
if fFileSize - FfrontPointer - 4 > 0 then
aLeft := fFileSize - FfrontPointer - 4
else
aLeft := fFileSize - (FFrontPointer + 4 - fFileSize);
readbuffersize(Ffrontpointer, buffersize);
for i := 0 to buffersize div divAccount - 1 do
begin
if aLeft >= divAccount then
begin
blockRead(Q, buffer[1], divAccount, ActReadNum);
aStream.Write(buffer[1], divAccount);
aLeft := aLeft - divAccount;
if ActReadNum <> DivAccount then
begin
Result := -1;
exit;
end;
end
else
begin
blockRead(Q, buffer[1], aLeft, ActReadNum);
astream.Write(buffer[1], aLeft);
aLeft := fFileSize - ffrontPointer;
if ActReadNum <> aLeft then
begin
Result := -1;
exit;
end;
Seek(Q, 512);
blockRead(Q, buffer[1], divAccount - aLeft, ActReadNum);
astream.write(buffer[1], divAccount - aLeft);
aLeft := aLeft - (divAccount - aLeft);
if ActReadNum <> divAccount - aLeft then
begin
Result := -1;
exit;
end;

end;
end;
//如果还有剩余
if bufferSize mod divAccount <> 0 then
begin
if aleft >= bufferSize mod divAccount then
begin
blockRead(Q, buffer[1], bufferSize mod divAccount, actReadNum);
aStream.Write(buffer, bufferSize mod divAccount);
if ActReadNum <> DivAccount then
begin
Result := -1;
exit;
end;
end
else
begin
blockRead(Q, buffer[1], aLeft, actReadNum);
aStream.Write(buffer[1], aLeft);
if ActReadNum <> DivAccount then
begin
Result := -1;
exit;
end;
Seek(Q, 512);
blockRead(Q, buffer[1], bufferSize mod divAccount - aleft, actReadNum);
aStream.Write(buffer[1], bufferSize mod divAccount - aleft);
if ActReadNum <> DivAccount then
begin
Result := -1;
exit;
end;
end;
end;
finally
//离开互斥状态
releaseMutex(hMutex);
end;
end;
end;

//读取磁盘队列一条内容
function TcommQueue.readqueue(var buffer
var size: longint): integer;
var
recvstream: TmemoryStream;
begin
result := 1;
if empty = 1 then
begin
result := -1
//队列已空
exit;
end;
//创建接收的内存流
recvStream := TMemoryStream.Create;
//调用ReadStream,从磁盘队列读出一条内容
readStream(recvStream);
recvStream.Seek(0, 0);
//将流写入Buffer
recvStream.Read(Buffer, recvStream.Size);
size := recvStream.Size;
//指针向后移动一位
Ffrontpointer := addone(Ffrontpointer);
writeheadfront(Ffrontpointer);
end;

//将流写入磁盘队列
function TCommQueue.writeStream(aStream: TMemoryStream): integer;
var
buffer: array[1..divAccount] of char;
i: integer;
ActWriteNum: Longint;
aleft: Longint;
begin
Result := 1;
//进入互斥,阻止其他线程访问
if waitForSingleObject(hMutex, INFINITE) = WAIT_OBJECT_0 then
begin
try
//判断底部剩余空间是否大于4,以判断是否分开写
if fFileSize - Frearpointer - 4 > 0 then
aLeft := fFileSize - Frearpointer - 4
else
aLeft := fFileSize - (FrearPointer + 4 - fFileSize);
aStream.Seek(0, 0);
for i := 0 to aStream.Size div divAccount - 1 do
begin
if aLeft >= divAccount then
begin
aStream.Read(buffer[1], divAccount);
blockWrite(Q, buffer[1], divAccount, ActWriteNum);
aLeft := aLeft - divAccount;
if ActWriteNum <> DivAccount then
begin
Result := -1;
exit;
end;
end
else
begin
astream.Read(buffer[1], aLeft);
blockWrite(Q, buffer[1], aLeft, ActWriteNum);
aLeft := fFileSize - ffrontPointer;
if ActWriteNum <> aLeft then
begin
Result := -1;
exit;
end;
Seek(Q, 512);
astream.Read(buffer[1], divAccount - aLeft);
blockWrite(Q, buffer[1], divAccount - aLeft, ActWriteNum);
aLeft := aLeft - (divAccount - aLeft);
if ActWriteNum <> divAccount - aLeft then
begin
Result := -1;
exit;
end;

end;
end;
if aStream.Size mod divAccount <> 0 then
begin
if aleft >= aStream.Size mod divAccount then
begin
aStream.read(buffer[1], aStream.Size mod divAccount);
blockWrite(Q, buffer[1], aStream.Size mod divAccount, actWriteNum);
if ActWriteNum <> DivAccount then
begin
Result := -1;
exit;
end;
end
else
begin
aStream.Read(buffer[1], aLeft);
blockWrite(Q, buffer[1], aLeft, actWriteNum);
if ActWriteNum <> DivAccount then
begin
Result := -1;
exit;
end;
Seek(Q, 512);
aStream.Read(buffer[1], aStream.Size mod divAccount - aleft);
blockWrite(Q, buffer[1], aStream.Size mod divAccount - aleft, actWriteNum);
if ActWriteNum <> DivAccount then
begin
Result := -1;
exit;
end;
end;
end;
finally
//离开互斥
releaseMutex(hMutex);
end;
end;
end;

function TcommQueue.writequeue(const Buffer
const size: integer): integer;
var
SendStream: Tmemorystream;
leftsize: longint;
begin
result := 1

getleftsize(leftsize);
if leftsize < size + 4 then
begin
result := -1

exit;
end;
try
sendStream := Tmemorystream.Create;
sendStream.WriteBuffer(buffer, size);
sendStream.Seek(0, sofrombeginning);
WriteBufferSize(Frearpointer, size);
writeStream(sendStream);
Frearpointer := addone(Frearpointer);
writeheadrear(Frearpointer);
finally
sendStream.Free;
end;
end;

function TcommQueue.addone(var position: longint): longint;
var
buffersize: longint;
nextposition: longint;
begin
readFileSize;
readbuffersize(position, buffersize);
nextposition := position + 4 + buffersize;
if nextposition > FFileSize then
begin
if Fscroll = 'Y' then
Fscroll := 'N'
else
Fscroll := 'Y';
writescroll(Fscroll);
result := (position + 4 + buffersize) mod FFileSize + 512;
end
else
result := position + 4 + buffersize;
end;

end.
 
后退
顶部