C++Builder 程序员博客
5 Sep
有一个函数,运行需要很长时间.
void fun();
假如button1用来执行这个fun(),
如果等不了,我想按button2停止这个函数.
想到的办法是将fun放在一个线程的execute()里.
刚才看了一下文档,Thread->Terminate();函数并不能结束该线程,而只是将它的Terminated属性改为true;
这怎么办呢?
可以在线程的函数Excute里面
void __fastcall TChangeLabel::Execute() { if(!Terminated) { //你这个里面要做的事情 } //—- Place thread code here —- }
当你Terminate()时函数线程里面就不会执行了
if(!Terminated)
{
fun();
}
关键就是fun();函数还在执行,你无法中断它
那你还是在函数里面设置一个标志好了,为true是返回就ok了
2楼的做法是最恰当的。
强制退线程只有用:BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。各参数含义如下:
hThread:将被终结的线程的句柄;
dwExitCode:用于指定线程的退出码。
使用TerminateThread()终止某个线程的执行是很不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,一般不建议使用该函数。
建议还是采用Thread->Terminate();
并在fun()中加检查Terminated标志的代码来确定是否需要退出执行
4 Sep
做一个测试软件模拟多个客户端连接到服务器端,客户端采用多线程处理方式。
实现方式 :在线程中定义TClientSocket * FClientSocket;
TWinSocketStream* FSocketStream;
unsigned char FAcceptBuff[500];
unsigned char FSendBuff[200];
线程构造函数中初始化上面的对象
{
FClientSocket = new TClientSocket(NULL); //
FSocketStream = new TWinSocketStream(FClientSocket,1000);
memset(FAcceptBuff,00,500);
memset(FSendBuff,00,200);
FClientSocket … 设置阻赛,端口,主IP,并打开连接
}
在OnExecute 中
while ((!Terminated)&& FClientSocket->Active)
{
Sleep(30);
if (FSocketStream->WaitForData(100))
{
//—————问题出现在下面
/* 如果创建一个线程正常,如果创建多个线程则出现
… read error 64,指定的网络名不再可用。 …
查找相关内容是说相关连接已经关闭。
各位大侠帮忙解释一下,什么原因,如何造成的,如何解决呢??
*/
RecvLen = FSocketStream->Read(FAcceptBuff,500);
//—————-
if ( RecvLen > 0)
{
FAcceptDataCount++; //计数
ReadSocket(FAcceptBuff,RecvLen); //接收缓冲区处理缓冲区数据
FMessage.LParamHi = FAcceptDataCount; //消息通知主线程
FMessage.LParamLo = FSendDataCount;
PostMessage(FMainHandle,CCMESSAGE,(unsigned int)FThreadID,FMessage.LParam);
}
}
}
/* 如果创建一个线程正常,如果创建多个线程则出现
… read error 64,指定的网络名不再可用。 …
查找相关内容是说相关连接已经关闭。
各位大侠帮忙解释一下,什么原因,如何造成的,如何解决呢??
*/
3 Sep
程序中用一个线程(Thread1)合并一个文件夹下的所有文件并创建一个新文件file.txt,然后将这个 file.txt 装入到Memo中,另一个线程(Thread2)对Memo中的内容进行处理,因为file.txt比较大,文件装入到Memo中需要一段时间,这样Thread2对Memo的内容进行处理时就有问题,请问怎么让Thread1执行完后再启动Thread2?
线程一的代码是:
Form1->MergerFile("c:\\log\\");//合并文件
Form1->Memo1->Lines->LoadFromFile("c:\\log\\one.txt");//装入文件
WaitForSingleObject等待线程1的结束
21 Aug
初学线程,见笑挖:
我想用一个按钮来激发一个线程,线程作用就是写一个txt文件;现在我不知道如何调用线程,我看过socket的例子,不过我只是在本地激发线程,并不通过clientsocket来判断,总之就一句话,搞不清楚怎么定义线程,及调用方法。
我是这么写的:
class MyThread : public TThread
{
private:
protected:
void __fastcall Execute();
public:
__fastcall MyThread(bool CreateSuspended);
}
这是线程的定义,我就不太清楚里面要怎么写,象那个createsuspended,Execute();我倒是写了应该没啥问题
然后就是调用:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
MyThread *mythread = new MyThread(false, Asocket);
}
这句老是报错,说MyThread 未定义,请各位赐教啊~
建议去看C++的书。关于类的继承的章节。
Cbuilder提供了TThread类
如果你用它 你需要重TThread继承写一个新的类。
你的mythread如果需要构造中传入2个参数。你需要修改你的MyThread的构造函数。
改为 __fastcall MyThread(bool CreateSuspended,Type Asocket);
该回复于2008-07-10 02:37:41被版主删除
该回复于2008-07-10 02:50:29被版主删除
该回复于2008-07-19 16:11:37被版主删除
7 Aug
CREATE PROCEDURE [dbo].[sp_RemoteAddEmployee] @dvcID bigint,@EmpID varchar(10),@Name varchar(10),@Company varchar(50),
@Post varchar(10),@PhoneNum varchar(15),@IdentityCard varchar(20),
@Note varchar(50),@Type tinyint,@FpData1 varbinary(512),
@FpData2 varbinary(512),@FpData4 varbinary(512),@PhotoData image,
@ErrorCode int output,@FpNo int output
AS
DECLARE @strSQL varchar(1024)
DECLARE @FingerNo int
set @FpNo = -1
BEGIN TRAN
–select TOP 20 FpNo = IDENTITY(int,1,1) into #t from syscolumns a
–生成指纹号码
select @FingerNo = CASE WHEN NOT EXISTS(select * from bEmployee_Inf where FingerSn = 1 and dvcID = @dvcID) THEN 1
ELSE
(
select MIN(FingerSn) + 1 from bEmployee_Inf a where NOT EXISTS(select * from bEmployee_Inf where FingerSn = a.FingerSn + 1) and dvcID = @dvcID
)
END
if exists(select ID from bEmployee_Inf where dvcID = @dvcID and IdentityCard = @IdentityCard)
begin
set @ErrorCode = 1
COMMIT TRAN
return
end
–set @index = 1
–Create Table #bFpNo from (select
insert into bEmployee_Inf (dvcID,EmpID,Name,Company,Post,PhoneNum,IdentityCard,Note,Type,FpData1,FpData2,FpData4,PhotoData,FingerSn) values
(@dvcID,@EmpID,@Name,@Company,@Post,@PhoneNum,@IdentityCard,@Note,@Type,@FpData1,@FpData2,@FpData4,@PhotoData,@FingerNo)
if @@ERROR <> 0 or @@ROWCOUNT = 0
begin
set @ErrorCode = 2;
ROLLBACK
return
end
COMMIT TRAN
set @ErrorCode = 0
set @FpNo = @FingerNo
GO
请问一下 这样的存储过程能保证 @FpNo 在同时操作的时候能保证是唯一的吗?就是不会同时产生相同的FpNo.
还有那个IdentitCard 在插入一条新纪录的时候能保证它的唯一性吗?
都不能保证唯一.
最好用字段来限制一下,例如主键设成FingerSn
那要怎样来保证呢?
主要有2种方法:
1. 使用generator,create generator是串行的,可以保证每次生成的ID是唯一的。不过不是所有的DBMS都支持。
2. 使用随机生成的序列号,检测碰撞,如果出现冲突再重新生成一个。
不是事务本身就有加锁的功能吗?
难道可以同时执行同一个事务?
顶一把,问题还是没人来解答啊
数据库本身的功能,比如事务等等,才能实现
6 Aug
本人最近有个软件要设计。遇到了一些问题,请大家知道一下。我用的是TCP socket连接方式。
客户端发来很多命令,命令种类就几种,我这边的处理方式:将所有的命令放在链表中,然后几种一个线程处理,效率不高,但是如果用多线程处理,虽然命令传过来是按顺序的,但是这边处理可能存在乱序处理,造成客户端响应不正确。应该怎么办呢?
既然客户端的命令是需要串行处理的,那就没必要使用多线程进行并行处理,因为服务器同一时间应该不只是一个客户端,同一时间可以只分派一个线程来处理某一个客户连接的命令.另外一种就是对这些数据处理完之后进行一个排队之后再返回给客户端.
客户端既然可以进行命令的异步发送,那么命令跟命令之间就不应该存在先后依赖关系.那么问题就转变为仅仅只是客户端无法误别当前返回的数据是哪一个命令的应答,而如果你在应答内容当中增加上一个可语别的标识不就可以解决了?
是这样的,如果客户先后发送两条请求过来,我这边的接受顺序应该是正常的,但是如果由多个线程统一处理,如果处理结果存在乱序,这样返回给客户的处理就是错误的,这样会导致问题的。
而且向这种异步接受多客户端的命令,统一处理,在转发给多服务后端来满足客户请求的情况,可以采取什么设计模式呢。以前不认人考虑命令种类有限,考虑命令模式,但是好像命令封装不好,命令中处理的资源很多是全局的,封装性有问题,有没有别的比较合适的模式呢?求教!
….
可以由多个服务线程来处理多个不同的客户端请求;
另外安排一个线程专门用于返回信息给客户端,该线程负责按时序来获取各请求处理的结果,并逐一回应给客户端。
接收到的放到一个队列,然后由其他线程去取,应该没问题
3 Aug
进程的主线程句柄与该进程的句柄有什么不同?
句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?
为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。
1 Aug
我用IDTCPCLIENT 新开了一个线程用WHILE(TRUE)来接收数据
数据倒是一条不漏能接收到 但是主窗体不响应消息..
/*线程内的方法*/
void __fastcall TCPR::Recv(){
AnsiString msg="";
while(recvflag&&TC->Connected()){
msg=TC->IOHandler->ReadLn();
if(msg!="")DoRecv(this,msg);
}
}
29 Jul
不记得在哪里看到过一句话,说list,或者是TList不是线程安全的.
有一个线程安全的版本是….
谁晓得这个?
需要安全的话,你自己加一个锁就可以了。
TList 是线程不安全的!
可以使用TThreadList
TThreadList *hThreadList = new TThreadList();
hThreadList->LockList();
hThreadList->Add(void*);
hThreadList->Unlocklist();
其实ThreadList 就是封装了TList + 临界段来实现的
该回复于2008-07-29 09:17:35被版主删除
要线程安全,可以用TThreadList
说明下,
如果用TThreadList,则在调用Add和Remove时都是不需要调用LockList(); 和Unlocklist(); 的,该类已经对这两个方法进行了保护;
如果需要获取到实际的TList对象,则必须用LockList(); 和Unlocklist(); ,
如下:
TList * list=hThreadList->LockList();
//此时正常操作list
hThreadList->Unlocklist();
TThreadList
是线程安全的。
21 Jul
主线程接收了一个消息
然后想要传递给 子线程所创建的form内的RichEdit 加以显示
可是偏偏就这里出错
pThread->pChatForm->RichEdit1->Lines->Add(strTemp);
pThread是子线程指针
pChatForm是子线程中的form指针
莫非不能这样调用?
请高人指点
具体代码如下
void __fastcall Domessage(AnsiString strTemp)
{
//TODO: Add your source code here
int iTemp;
AnsiString strSub;
Chatcontrol *pThread;
USER uTemp;
iTemp = strTemp.Pos(',');
strSub = strTemp.SubString(1,iTemp-1);
strTemp.Delete(1,iTemp);
uTemp.strLockid = strSub;
uTemp.strName = "陌生人"+uTemp.strLockid;
iTemp = strTemp.Pos(',');
strSub = strTemp.SubString(1,iTemp-1);
strTemp.Delete(1,iTemp);
if(strSub != MainForm->User.strLockid)
return;
//处理消息
ShowMessage(strTemp);
iTemp = MainForm->SearchThread(&uTemp);
if(iTemp < 0)
{
if(MainForm->NewThread(&uTemp) == false)
{
ShowMessage("新建窗口错误");
return;
}
pThread = MainForm->pTList[MainForm->iTNum-1];
}
else
pThread = MainForm->pTList[iTemp];
if(pThread->pChatForm != NULL)
{
pThread->pChatForm->RichEdit1->Lines->Add(strTemp);
ShowMessage("窗口成功!");
}
}