为了正常的体验网站,请在浏览器设置里面开启Javascript功能!
首页 > [训练]未成年人犯罪是指已满14周岁

[训练]未成年人犯罪是指已满14周岁

2017-11-10 6页 doc 19KB 3阅读

用户头像

is_482581

暂无简介

举报
[训练]未成年人犯罪是指已满14周岁BCB多线程编程 大家可能经常听说“线程”这个词汇:网络蚂蚁采用了多线程下载技术、FoxMail采用了多线程收信技术等等,可能有人就会问:什么是线程呢? 一、什么是线程 对于初次接触“线程”这个概念的人来说,会对线程这个概念有点模糊,特别是对线程、进程、程序这三个概念的区别和联系不太清楚,所谓程序,其实就是磁盘上的可执行的文件,只有当它被启动后才成为一个进程;而进程指一个当前装载到内存中的程序;进程不做任何事,它们只是存在,真正从事某项任务的是才是线程。 多线程看上去比较复杂和神秘。的确,像线程同步、线程局部存储(T...
[训练]未成年人犯罪是指已满14周岁
BCB多线程编程 大家可能经常听说“线程”这个词汇:网络蚂蚁采用了多线程下载技术、FoxMail采用了多线程收信技术等等,可能有人就会问:什么是线程呢? 一、什么是线程 对于初次接触“线程”这个概念的人来说,会对线程这个概念有点模糊,特别是对线程、进程、程序这三个概念的区别和联系不太清楚,所谓程序,其实就是磁盘上的可执行的文件,只有当它被启动后才成为一个进程;而进程指一个当前装载到内存中的程序;进程不做任何事,它们只是存在,真正从事某项任务的是才是线程。 多线程看上去比较复杂和神秘。的确,像线程同步、线程局部存储(TLS)以及相关的内容确实有其复杂的一面。不过,我相信你会很惊讶地发现,在程序中加入线程是那么的简单,甚至与线程同步的内容,诸如临界、互斥也很简单,至少在原理上是这样。 下面就以一个简单的例子来进一步介绍多线程,这个例子演示了如何创建一个简单的线程。 二、一个简单的多线程程序 新建一个项目,在上面加入两个按钮,名为bUseThread和bNoThread,用来选择单线程还是多线程,然后在程序中加入下面的函数: DWORD CALLBACK ThreadFunc(void *p) { HDC DC=GetDC(Form1->Handle); for(int i=0;i<1000000;i++) { String s=i; TextOut(DC,10,10,s.c_str(),s.Length()); } ReleaseDC(Form1->Handle,DC); return 0; } CALLBACK示这是一个回调函数,在我们创建线程时需要回调函数,它也可以象普通函数一样被调用。这个函数的功能是在窗口(10,10)的地方显示0——1000000,1000000这个数是为了能看清楚程序运行而设的,你可以依据你机器的速度来修改这个值。 然后,在bNoThread的onClick事件句柄中加入以下代码: ThreadFunc(0); 这就是普通方式来调用前面函数。 然后在bUseThread的onClick事件句柄中加入以下代码: DWORD ThreadID; HANDLE hthread=CreateThread(0,0,ThreadFunc,0,0,&ThreadID); if(hthread==0) ShowMessage("NO Thread"); API函数CreateThread()的功能是创建一个线程,它的函数原型是: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性指针DWORD dwStackSize, // 初始化线程的栈,以字节为单位 LPTHREAD_START_ROUTINE lpStartAddress, // 线程的入口函数 LPVOID lpParameter, // 新线程的参数 DWORD dwCreationFlags, // 设置线程的标志 LPDWORD lpThreadId // 线程的ID号); 其中第一个参数设置成0表示使用默认的安全属性,如果希望子进程能够继承该线程,则需要设置安全属性。要了解更多信息,请参阅WIN32帮助文件中的SECURITY_ATTRIBUTES部分。 第二个参数设置成0表示线程所能使用的栈的大小与应用程序的栈的大小相同,换句话说,主线程和正在创建的线程有同样大小的栈。如果需要的话,栈的大小会自动增加。简而言之,这个参数一般设置成0即可。 lpStartAddress 参数是这个函数最重要的参数,用于指定线程开始运行时要调用的线程函数的名称。线程函数必须具有下列格式: DWORD CALLBACK ThreadFunc(void *p) lpParameter 是传递给线程函数的参数,也就是上面的void *p,也就是说,可以传递任何类型的参数的指针给回调函数。 dwCreationFlags 用于设置线程的标志,目前唯一可用的是CREATE_SUSPENDED,创建一个挂起的线程。 lpThreadId 是一个DWORD的指针,当线程创建成功时,用这个参数返回线程的ID。 运行程序可以看出,在使用多线程时,程序在计数时你可以移动窗口,改变窗口大小等,而不使用多线程时,在计数的同时是不能够改变窗口大小和移动窗口的,不信你就在分别单击两个按钮后把鼠标移动到窗口边缘试试。 多线程编程是提高系统资源利用率的一种常见方式。它占用的资源更小,启动更快,还可以实现在后台运行一些需时较长的操作。 一、初识TThread对象 VCL提供了用于多线程编程的TThread类,在这个类中封装了Windows关于线程机制的Windows API,通常将它的实例成为线程对象。线程对象通过封装简化了多线程应用程序的编写。注意,线程对象不允许控制线程堆栈的大小或安全属性。若需要控制这些,必须使用Windows API的CreateThread()或BeginThread()函数。不过,即使是使用Windows Thread API函数建立和控制多线程,仍然可从一些同步线程对象或下节将要描述的方法中受益。 要在应用程序中使用线程对象,必须创建TThread的一个派生类。File|New|Thread Object,系统会提示为新线程对象提供类名,我们将其命名为TMyThread。我们必须自行在构造函数以及Execute()函数中添加代码。自动生成的构造函数中有一个参数,如果为true的话线程创建后将进入挂起状态,直到线程对象的Resume()函数被调用才开始执行。如果为false则线程创建后会立刻开始执行。 我们先创建一个实例来亲自感受下多线程:在窗体上放两个Button和两个Edit组件,自动命名。然后File|New|Thread Object来创建一个线程对象,命名为TMyThread。 以下请看完整代码: //Unit1.h //主窗体头文件 //--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include #include #include #include #include "Unit2.h" //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TButton *Button1; TButton *Button2; TEdit *Edit1; TEdit *Edit2; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); void __fastcall FormCreate(TObject *Sender); private: // User declarations TMyThread *thread1,*thread2; public: // User declarations __fastcall TForm1(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif //Unit1.cpp //主窗体实现文件 //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { thread1->Resume(); //单击后才启动线程 } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { thread2->Resume(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { thread1=new TMyThread(true,Edit1); //创建线程对象实例thread2=new TMyThread(true,Edit2); } //--------------------------------------------------------------------------- //Unit2.h //线程类头文件 //--------------------------------------------------------------------------- #ifndef Unit2H #define Unit2H //--------------------------------------------------------------------------- #include //--------------------------------------------------------------------------- class TMyThread : public TThread { private: TEdit *edResult; //自定义局部变量 String strResult; protected: void __fastcall Execute(); void __fastcall ShowResult(); //自定义函数 public: __fastcall TMyThread(bool CreateSuspended,TEdit *AEdit); //注意:修改了默认参数}; //--------------------------------------------------------------------------- #endif //Unit2.cpp //线程类实现文件 //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit2.h" #pragma package(smart_init) //--------------------------------------------------------------------------- __fastcall TMyThread::TMyThread(bool CreateSuspended,TEdit *AEdit) : TThread(CreateSuspended) { edResult=AEdit; } //--------------------------------------------------------------------------- void __fastcall TMyThread::Execute() { for(int i=0;i<200;i++) { strResult=IntToStr(i); Synchronize(ShowResult); //管理线程同步,保证安全性 Sleep(100); } } //--------------------------------------------------------------------------- void __fastcall TMyThread::ShowResult() { edResult->Text=strResult; } //--------------------------------------------------------------------------- 然后我们F9运行程序就可以查看效果了。 二、编写线程函数 Execute()函数就是线程函数,它包含了程序中所有需要并行执行的代码。除了共享相同的进程空间外,可以认为线程就是通过应用程序启动的程序。但在编写线程函数的时候需要注意与单独程序的不同之处。因为线程与其他线程共享内存空间,所以必须确认没有覆盖应用程序中其它线程的内存地址。而另一方面,可以使用共享内存在线程之间进行通信。 在线程函数内部,我们可以使用任意的全局变量,但有些变量我们并不希望同一线程类的其他实例共享它,就可以声明一个线程(thread-local)变量。通过将__thread修饰语加入变量声明就可以声明一个线程变量。例如int __thread x; 声明一个整型变量。 __thread修饰语只可用于全局(文件范围)或静态变量。指针和函数变量不能作为线程变量。使用“在写入时复制”语法的类,如AnsiStrings也不能作为线程变量。需要在运行时进行初始化或析构的类型也不能被声明为__thread类型。 当程序中调用Resume()函数时,线程启动并继续执行直到Execute()结束。这就是线程执行特定任务,并在其完成时终止的模式。然而,有时应用程序需在一些外部条件满足时终止线程。通过检查Terminated属性可允许其它线程本线程终止。当其它线程试图终止本线程时,它调用Terminate()函数。Terminate()函数将本线程的Terminated属性设置为true。Execute()函数通过检查和响应Terminated属性来实现Terminate()函数。下面的实例演示了这种做法: void __fastcall TMyThread::Execute() { while( !Terminated ) { } } 在线程函数终止时我们可能需要做一些清理工作。由于在线程终止前,OnTerminate事件会发生,所以我们可以将清理代码放在OnTerminate 事件处理程序中,这样可确保不管Execute()函数如何执行,清理代码总是可以被执行。要注意OnTerminate事件处理程序不作为线程的一部分运行,而是在应用程序的主线程中执行的。这意味着: (1)在OnTerminate事件处理程序中不能使用任何线程局部变量。 (2)在OnTerminate事件处理程序中可安全地访问任何组件及VCL对象而不会和其他线程发生冲突。 三、协调线程 在编写线程执行时运行的代码时,必须考虑到可能同步执行的其他线程行为。主要有两种情况:一个是避免两个线程试图同时使用某一个全局对象或变量;另一个是某线程中的一些代码可能会依赖其他线程所执行任务的结果。 1,避免同时访问 为避免在访问全局对象或变量时与其他线程发生冲突,可能需要暂停其他线程的执行,直到该线程代码完成操作。这里需要注意,不要暂停其他不需停止的线程执行,这样会使效率严重降低,也无法获得使用多线程的优点。 <1>,锁定对象 一些对象内置了锁定功能,以防止其他线程使用该对象的实例。例如,画布对象(TCanvas及其派生类)有一种Lock()函数可防止其他线程访问画布,直到调用Unlock()函数。 VCL还包含一种线程安全的列表对象TThreadList。调用TThreadList::LockList()返回列表对象,同时组织其他线程使用列表直到调用UnlockList()函数。调用TCanvas::Lock()函数或TThreadList::LockList()函数时可以安全地嵌套。锁定直到最后一个锁定调用匹配到同一线程中相应的解锁调用时才会被释放。 显然这种方法只对部分类有效。 <2>,使用重要区段 若对象没有提供内置的锁定功能,可使用重要区段。重要区段像门一样,每次只允许一个线程进入。要使用它,需创建TCriticalSection的全局实例。TCriticalSection有两个函数:Acquire()(阻止其他线程执行该区段)以Release()(取消对其他线程的阻止)。 每个重要区段都与需要保护的全局内存关联。每个要访问这个全局内存的线程首先要调用Acquire()函数以确保其他线程不能访问它。当线程结束时,要调用Release()函数以便其他线程能继续访问。例如,应用程序有一个全局重要区段变量pLockXY,可阻止访问全局变量X和Y。任何使用X或Y 的线程必须调用重要区段,如下所示: pLockXY->Acquire(); try{ Y=sin(X); } __finally { pLockXY->Release(); } <3>,使用多重读、独占写的同步器 当使用重要区段来保护全局内存时,每次只有一个线程可以使用该内容。这种保护可能超出了需要,特别是当有一个经常读但很少写的对象或变量时更是如此。多个线程同时读相同内存但没有线程写 内存是没有危险的。当有一些经常被读但很少有线程向其写入的全局内存时,可使用TMultiReadExclusiveWriteSynchronizer对象保护它。这个对象与重要区段一样,但它允许多个线程同时读,只要没有线程写即可。线程必须有独占访问权才能写使用TMultiReadExclusiveWriteSynchronizer保护的内存。 要使用“多重读、独占写”的同步器,需创建TMultiReadExclusiveWriteSynchronizer的一个全局实例,它与要保护的全局内存关联。每个需要读内存的线程首先要调用BeginRead()函数。它确保当前无其它线程写内存。线程完成读操作后调用EndRead()函数。任何线程要写内存的时候必须先调用BeginWrite()函数,结束后调用EndWrite()函数。 <4>,共享内存的其他技术 当使用VCL对象时,使用主VCL线程来执行代码,可确保对象不会间接地访问同时被其他线程中的VCL对象使用的内存。若全局变量不需要被多个线程共享,可使用线程变量来代替它。线程可以不需要等待或暂停其他线程。 2,等待其他线程 若线程必须等待另一线程完成某项任务,可让线程临时中断执行。然后要么等待另一线程完全执行结束,要么等到另一线程通知完成了该项任务。 <1>,等待线程执行结束 要等待另一线程执行结束,使用它的WaitFor()函数。WaitFor()函数直到那个线程终止才返回,终止的方式要么完成了Execute()函数,要么由于一个异常。例如,下面的代码在访问列表中的对象前等待,直到另一线程填满该列表。 void __fastcall TVisitList::Execute() { int fileRes; TFillThread *fl=new TFillThread(false); fillRes=f1->WaitFor(); //以下进行后续处理 } 上例中,列表对象只在WaitFor()函数指出该列表被填满时才能被访问。返回值由被等待线程的Execute()函数指定。然而,因为调用WaitFor()函数的线程需要直到另一线程的执行结果,无法以代码调用Execute()函数,Execute()函数也无法返回任何值。所以TFillThread线程的Execute()函数应该设置ReturnValue属性。ReturnValue通过被其他线程调用的WaitFor()函数返回。返回值是一个证,由应用程序确定其含意。 <2>,等待任务完成 有时,只需等待线程完成一些操作而不是执行结束。为此,可使用一个事件对象。事件对象(TEvent)应具有全局范围以便他们能够为所有线程可见。当一个线程完成一个被其他线程依赖的操作时,调用TEvent::SetEvent()函数。它发出一个信号,以便任何其他线程可检查并得知操作完成。要关掉信号 则使用ResetEvent()函数。 四、调试多线程程序 当调试多线程应用程序时,试图跟踪所有并行线程的状态,或在断点停止时判断是哪一个线程的执行往往会使人感到迷惑。可使用Thread Status框来帮助跟踪并控制应用程序中所有的线程。开启Thread Status框的方法是:View|Debug Windows|Threads。 当一个调试事件(断点、异常、暂停)发生时,线程状态指示各个线程的状态。右击可定位相应的源代码位置或将其他线程设置为当前线程等。 最后要提醒的是,不要使用无意义的多线程。如果一段程序完全是串行的,每一步的操作都需要上一步的结果,那么在这里采用多线程技术就是毫无意义的。
/
本文档为【[训练]未成年人犯罪是指已满14周岁】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索