关于多线程和Timer的问题(100分)

  • 主题发起人 firstrose
  • 开始时间
F

firstrose

Unregistered / Unconfirmed
GUEST, unregistred user!
我的程序里用了2个线程,分别用2个Timer每隔40秒触发一次。这样是否合适?
线程里没有while not Terminateddo
就这样,cpu占用率有80%,这是怎么回事,和Timer有关系吗?
 
while not Terminated 往往不好使的.
我一般的做法是在线程类中加一个布尔变量
在其Destroy中设置变量值.
比如While thrSearch.IsStoped then

do
sth.
 
你用定时器对象试试!它属于内核对像是线程安全的!
C++语言的。。。
HANDLE hTime = CreateWaitableTimer(
NULL,
true,
NULL);
//创建一个时间对像。
SetWaitableTimer(
hTime,
40 * 1000 //定时器什么时候第一次报时
40 * 1000 //定时器每隔多久报时一次
NULL,
NULL,
false);
//设置定时器
WaitForSngleObjecEx(
hTime,
INFINTE,
true);
//线程等待hTime时间对像
 
http://chinaour.com/?own_delphi
 
线程本身可以用做定时器,下面是一段示例代码:
procedure TTimerThread.Execute;
var
WaitTime: DWORD;
begin
while not Terminateddo
begin
if FInterval = 0 then
WaitTime := INFINITE
else
WaitTime := FInterval;
//等待事件对象进入发信号状态;
if WaitForSingleObject(FStopEvent, WaitTime) = WAIT_TIMEOUT then
Synchronize(FOwner.DoTimer);
end;
CloseHandle(FStopEvent);
end;
 
怎么回答文不对题?
 
怎么文不对题了?这就是告诉你不要用Timer嘛。
 
那两个线程是对摄像头采集的数据进行压缩/解压缩并且回放。
因为每秒就20帧,我就没有用轮询了,而是用Timer去触发。
你的程序等于是轮询了。
而我的问题是cpu占用率有80%和Timer有关系没有。你就说
不要用Timer,那原因呢?我如果按照你的方法,不还要轮询嘛?
我现在的目标是尽量降低cpu占用率。最好像netmeeting那样,就23
 
请教一下楼主,你怎么用timer触发线程的?如果你不是用的thx1180或sunsong的方法,不知道你用的是什么方法实现的???
 
Timer是用消息机制工作的。
 
就这样
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
VDC.Execute;
end;
 
没见过这样用的,没有创建也没有释放吗?
多放些代码让大家帮你看看吧
 
要看你的代码才行,2个Timer每隔40秒触发一次按道理不会造成cpu占用率有80%。
 
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, VideoDisp, Videocap, Contnrs, variable, DataPack, vfw, ExtCtrls,
ScktComp, ACMOut, ACMIn, ACMConvertor, Menus, IdTCPConnection,
IdTCPClient, IdBaseComponent, IdComponent, IdTCPServer;
type
TMainForm = class(TForm)
VideoCap: TVideoCap;
VideoDisp: TVideoDisp;
btnStart: TButton;
btnStop: TButton;
Memo: TMemo;
Timer1: TTimer;
Timer2: TTimer;
AddrEdit: TEdit;
btnConnect: TButton;
ACMIn: TACMIn;
ACMOut: TACMOut;
MainMenu1: TMainMenu;
mmFile: TMenuItem;
lReceive: TLabel;
lPreview: TLabel;
btnExit: TButton;
btnDisconnect: TButton;
btnPause: TButton;
IdTCPServer: TIdTCPServer;
IdTCPClient: TIdTCPClient;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
procedure btnStartClick(Sender: TObject);
procedure VideoCapVideoStream(sender: TObject;
lpVhdr: PVIDEOHDR);
procedure btnStopClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketAccept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ACMInBufferFull(Sender: TObject;
Data: Pointer;
Size: Integer);
procedure btnExitClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;
implementation
{$R *.DFM}
Uses Player,Compress,Send;

procedure TMainForm.FormCreate(Sender: TObject);
Var
Vheader:TBitmapInfoHeader;
begin
VideoCap.DriverOpen:=False;
VideoCap.DriverIndex:=0;
HasVideo:=True;
Try
VideoCap.VideoPreview:=True;
Except
On ENotConnectExceptiondo
HasVideo:=False;
end;

If HasVideo then
begin
VHeader:=Videocap.BitMapInfoHeader;
VHeader.bicompression:=bi_RGB;
// Always RGB-Data
VHeader.biBitCount:= 24;
VideoCap.BitMapInfoHeader:= VHeader;
End
else
With VHeaderdo
begin
biSize:=40;
biWidth:=200;
biHeight:=150;
biPlanes:=1;
biBitCount:=24;
biCompression:=0;
biSizeImage:=57600;
biXPelsPerMeter:=0;
biYPelsPerMeter:=0;
biClrUsed:=0;
biClrImportant:=0;
end;

OriBMH:=VHeader;
CodedBMH:=QueryVideoCodec(OriBMH);

ACMOut.Open(ACMWaveFormat);
VideoDisp.Streaming:= true;
VideoDisp.BitMapInfoHeader:= VHeader;
If HasVideo then
VideoCap.DriverOpen:=True;

// ServerSocket.Open;
OriFrame:=TQueue.Create;
CodedFrame:=TQueue.Create;
OriFrame1:=TQueue.Create;
CodedFrame1:=TQueue.Create;
OriAudio:=TQueue.Create;
OriAudio1:=TQueue.Create;
D2Q:=Data2Queue.Create(OriFrame);
// Q2D:=Queue2Data.Create(OriFrame);
myPlayer:=TPlayer.Create(OriFrame1,OriAudio,HasVideo);
VC:=VideoCompressor.Create(OriBMH,CodedBMH,OriFrame,CodedFrame);
VDC:=VideoDeCompressor.Create(OriBMH,CodedBMH,CodedFrame,OriFrame1);
end;

procedure TMainForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
VDC.Terminate;
VC.Terminate;
VDC.Free;
VC.Free;
myPlayer.Free;
// Q2D.Free;
D2Q.Free;
OriAudio1.Free;
OriAudio.Free;
CodedFrame1.Free;
OriFrame1.Free;
CodedFrame.Free;
OriFrame.Free;
// ServerSocket.Close;
VideoDisp.Streaming:= false;
VideoCap.DriverOpen:=False;
ACMOut.Close;
end;

procedure TMainForm.btnStartClick(Sender: TObject);
begin
Timer1.Enabled:=True;
Timer2.Enabled:=True;

If HasVideo then
VideoCap.StartCapture;
ACMIn.Open(ACMWaveFormat);
end;

procedure TMainForm.VideoCapVideoStream(sender: TObject;
lpVhdr: PVIDEOHDR);
Const
KeyFrame:Boolean=True;
begin
D2Q.Convert(lpVhdr^.lpData^,lpVhdr^.dwBytesUsed);
VC.Execute;
end;

procedure TMainForm.btnStopClick(Sender: TObject);
begin
ACMIn.Close;
If HasVideo then
VideoCap.StopCapture;
// Sleep(500);
Timer1.Enabled:=False;
// Sleep(500);
Timer2.Enabled:=False;
FreeResource;
end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
VDC.Execute;
end;

procedure TMainForm.Timer2Timer(Sender: TObject);
begin
myPlayer.Execute;
end;

procedure TMainForm.ACMInBufferFull(Sender: TObject;
Data: Pointer;
Size: Integer);
Var
p:^DataBuf;
i:Byte;
ap:pBufferType;
begin
ap:=Data;
For i:=1 to 20do
begin
GetMem(p,400+4);
p^.Size:=400;
Move(ap^[(i-1)*400+1],p^.Data,400);
OriAudio.Push(p);
end;
end;

end.
 
上面是主程序。如果要完整的程序,下载以下文件:
http://user1.7host.com/tjmovieclub/forum/image/VOIP.RAR.PNG
这是RAR文件
下载后去掉.PNG后缀即可。
 
使用线程不应该直接调用它的Execute方法,再应该使用Resume来恢复执行,对于CPU
占用率的问题,你可以把线程的优先级调低。
 
不对吧,我的线程又不是循环的,resume不行的。另外,我调了优先级,没用!
 
>VDC.Execute;
如果象你这样的话,你的线程方法是执行在主线程中的,没有起到线程的作用。
你的线程如果是建立后立即运行的(inherited create(false)),那么
VDC := TVDC.Create(传参数,如果有的话)
就行了,如果你的线程是建立后挂起的(inherited create(true)),那么
你应该使用 VDC.Resume 来运行它。
 
但为节省资源,我的线程里没有while,resume一次就结束了。
下次执行用resume就不对了吧?
 
建立时设置:
FreeOnTerminate := false;
//刚才打错了,呵呵
用完:
Thread1.Suspend;
再用:
Thread1.Resume;
 
顶部