Article View: borland.public.cppbuilder.nativeapi
Article #12450Re: Killing off a crashed thread
From: Rodolfo Frino
Date: Thu, 04 Dec 2003 14:03
Date: Thu, 04 Dec 2003 14:03
355 lines
13161 bytes
13161 bytes
This illustrative sample code shows how to terminate a thread by pressing an
emegency button
(your case will probably be a bit different, so this might not apply as is)
#include <vcl.h>
#include <windows.h>
#include <iostream.h>
#pragma hdrstop
#include "TerminatingAThread.h"
//--------------------------------------------------------------------------
-
#pragma package(smart_init)
#pragma resource "*.dfm"
#define TEST 0
const int THREADS_TOTAL = 2;
TForm1 *Form1;
DWORD WINAPI ChangeColorsThr1(LPVOID dummy);
DWORD WINAPI ChangeColorsThr2(LPVOID dummy);
// Array of Handles to threads
HANDLE hThreads[THREADS_TOTAL];
// Array of thread id's
DWORD id[THREADS_TOTAL];
HANDLE hMutex;
static int Count = 0;
const TColor Colors1[10] = {clNavy, clBlue, clGreen, clSilver, clYellow,
clPurple, clAqua, clLime, clMaroon, clRed};
const TColor Colors2[10] = { clWhite, (TColor)0x98fda1,
(TColor)0x67fdc1, (TColor)0xacfd34,
(TColor)0x897dfe, (TColor)0x11fdac,
(TColor)0x998aaa, (TColor)0x209451,
(TColor)0x18cdfe, (TColor)0xeedfca };
bool Emergency = false;
//--------------------------------------------------------------------------
-
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Color = (TColor)0xecc1a2;
Position = poScreenCenter;
// Create Controls
// Create Panel1
Panel1 = new TPanel(this);
Panel1->Parent = this;
Panel1->Top = 15;
Panel1->Left = 15;
Panel1->Width = 200;
Panel1->Height = 40;
// Create 6 labels
for (int i=0; i < ARRAYSIZE(Label); i++)
{
Label[i] = new TLabel(this);
Label[i]->Parent = this;
Label[i]->Left = 72;
Label[i]->Width = 100;
Label[i]->Height = 40;
Label[i]->Font->Size = 12;
Label[i]->Caption = "Label " + String(i);
}
// Set the position for the labels
Label[0]->Top = 80;
Label[1]->Top = 80 + 20;
Label[2]->Top = 80 + 2*20;
Label[3]->Top = 80 + 3*20;
Label[4]->Top = 80 + 4*20;
Label[5]->Top = 80 + 5*20;
Label[6]->Top = 80 + 6*20;
// Create Button1
Button1 = new TButton(this);
Button1->Parent = this;
Button1->Top = 230;
Button1->Left = 15;
Button1->Width = 200;
Button1->Height = 100;
Button1->Caption = "Start Threads";
Button1->OnClick = Button1Click;
// Create Button2 (EMARGENCY Terminate Thread)
Button2 = new TButton(this);
Button2->Parent = this;
Button2->Top = Button1->Top;
Button2->Left = Button1->Left + Button1->Width + 10;
Button2->Width = Button1->Width;
Button2->Height = Button1->Height;
Button2->Caption = "EMERGENCY BUTTON";
Button2->OnClick = Button2Click;
// Create Button3 (Close Handles)
Button3 = new TButton(this);
Button3->Parent = this;
Button3->Top = Button1->Top;
Button3->Left = Button2->Left + Button2->Width + 10;
Button3->Width = Button1->Width;
Button3->Height = Button1->Height;
Button3->Caption = "Close Handles";
Button3->OnClick = Button3Click;
for (int i = 0; i < THREADS_TOTAL; i++)
hThreads[i] = NULL;
}
//--------------------------------------------------------------------------
-
BOOL ChangePanelColors(HANDLE hMutex, int Thrid)
{
DWORD dwWaitResult;
// Request ownership of mutex.
// ---------------------------
// A thread gets ownership of a mutex by specifying
// a handle to the mutex in one of the wait functions.
// in this case the wait function is WaitForSingleObject().
// WaitForSingleObject inputs:
// 1- handle to mutex object
// 2- time-out interval (5000 milliseconds)
// Time that the thread will wait to get the ownership
// of the mutex. If the thread does not get the ownership
// of the mutex within time-out milliseconds, the thread
// will not execute.
// WARNING: A thread that uses a WaitForSingleObject()
// function with no time-out interval may cause the
// system to become deadlocked.
dwWaitResult = WaitForSingleObject(hMutex, 10000L); // Win32 API
switch (dwWaitResult)
{
// The thread got the mutex ownership.
// (The state of the specified object is signaled which means
// that ownership of the mutex object is granted to the low
// priority thread)
case WAIT_OBJECT_0:
__try
{
// Do the Task here
// Remove all test lines in the final project
for(int i = 0; i < 200; i++)
{
//************************************************
// TERMINATE THREAD IF EMERGENCY BUTTON IS PRESSED
if (Emergency)
break;
//************************************************
Form1->Label[2]->Caption = IntToStr(Count++);
if (Thrid == 0)
{
if (TEST) Sleep(500); // test
Form1->Panel1->Color = Colors1[i];
Form1->Panel1->Caption = "Thread " +
IntToStr(Thrid);
Form1->Panel1->Width = 200;
Form1->Label[0]->Caption = "ChangeColors: Thread " +
IntToStr(Thrid) + " " +
IntToStr(Colors1[i]);
Form1->Update();
if (TEST)
{
// The ReleaseMutex is for teaching purposes
only
// Normally one thread will finish its job and
then
// the mutex will be released
ReleaseMutex(hMutex); // test
Sleep(500); // test
}
}
else
{
if (TEST) Sleep(500); // test
Form1->Panel1->Color = Colors2[i];
Form1->Panel1->Caption = "Thread " +
IntToStr(Thrid);
Form1->Panel1->Width = Form1->Width -
2*Form1->Panel1->Left;
Form1->Label[1]->Caption = "ChangeColors: Thread " +
IntToStr(Thrid) + " " +
IntToStr(Colors1[i]);
Form1->Update();
if (TEST)
{
// The ReleaseMutex is for teaching purposes
only
// Normally one thread will finish its job and
then
// the mutex will be released
ReleaseMutex(hMutex); // test
Sleep(500); // test
}
}
}
}
__finally
{
// The __finally block of code is executed
// no matter how the __try block terminates
// (unless the __try block includes a call
// to the TerminateThread function).
// This prevents the mutex object from being
// abandoned inadvertently.
// Release ownership of the mutex object.
// While a thread has ownership of a mutex,
// it can specify the same mutex in additional
// wait-function calls without blocking its execution.
// This prevents a thread from deadlocking itself
// while waiting for a mutex that it already owns.
// However, to release its ownership, the thread must
// call ReleaseMutex once for each time that the mutex
// satisfied a wait.
if (!ReleaseMutex(hMutex)) // Win32 API
{
// Display the error
Form1->Label[4]->Caption = "Error";
Count = 0;
return false;
}
if (Thrid == 0)
{
// Use blue color for thread 0
Form1->Label[4]->Font->Color = clBlue;
Form1->Label[4]->Caption = "Thrread " + IntToStr(Thrid)
+ " Task Done " ;
}
else
{
// Use green color for thread 0
Form1->Label[5]->Font->Color = clGreen;
Form1->Label[5]->Caption = "Thrread " + IntToStr(Thrid)
+ " Task Done " ;
}
}
break;
// time-out limit reached, thread didn't get ownership of mutex
case WAIT_TIMEOUT:
Form1->Label[4]->Caption = "Thrread " + IntToStr(Thrid)
+ " Timeout" ;
return false;
// thread has get the ownership of the abandoned mutex.
case WAIT_ABANDONED:
return false;
}
return true;
}
//===============================================================
// Thread Functions
//===============================================================
DWORD WINAPI ChangeColorsThr1(LPVOID dummy)
{
// Thread function (Thread 1 start execution here)
ChangePanelColors(hMutex, 0);
return (DWORD)dummy;
}
DWORD WINAPI ChangeColorsThr2(LPVOID dummy)
{
// Thread function (Thread 2 start execution here)
ChangePanelColors(hMutex, 1);
return (DWORD)dummy;
}
//===============================================================
void __fastcall TForm1::Button1Click(TObject *Sender)
{
char string_passed_to_thread[100];
strncpy(string_passed_to_thread, "Parameter passed on to the thread",
100);
//-------------------------------------------------------------------
// Create Mutex
hMutex = CreateMutex(NULL, FALSE, "MutexToProtectAction"); // Win32 API
if (hMutex == NULL)
{
// error
ShowMessage("Cannot Create Mutex");
return;
}
//-------------------------------------------------------------------
// Create Threads (Win32 API)
// Thread 0
hThreads[0] = CreateThread(NULL, 0, ChangeColorsThr1, (LPVOID)0, NULL,
&id[0]);
// Thread 1
hThreads[1] = CreateThread(NULL, 0, ChangeColorsThr2, (LPVOID)0, NULL,
&id[1]);
Label[3]->Caption = "Threads Created";
Form1->Label[6]->Caption = "Handles are open";
}
//-------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
// EMERGENCY BUTTON
Emergency = true;
}
//--------------------------------------------------------------------------
-
void __fastcall TForm1::Button3Click(TObject *Sender)
{
for (int i = 0; i < THREADS_TOTAL; i++)
if (hThreads[i])
{
// Close Handles (Wi32 API)
CloseHandle(hThreads[i]);
Form1->Label[6]->Caption = "Handles have been closed" ;
}
}
Rodolfo
"bladder" <bladder@lardyboys.com> wrote in message
news:3fcf0500$1@newsgroups.borland.com...
>
> Hi there,
> I have a multi threaded application ( written in BCB5 ), which for safety
reasons, must recover when one of its threads gets stuck, or if the user
presses the big red emergency stop button.
>
> What I'd like to know is the recommended way that a thread can terminate
another thread( even if the thread is running ) and what cleaning up the
terminating thread should perform?
>
> Thanks
>
> bladder
>
>
Technical Details
Message-ID:
<3fcf3ebf@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailReferences:
<3fcf0500$1@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 10cc67,f3d1051f853af8a9 X-Google-Attributes: gid10cc67,public X-Google-ArrivalTime: 2003-12-04 06:09:35 PST From: "Rodolfo Frino" <MenInBlack@nowhere.com> Newsgroups: borland.public.cppbuilder.nativeapi References: <3fcf0500$1@newsgroups.borland.com> Subject: Re: Killing off a crashed thread Date: Fri, 5 Dec 2003 01:03:58 +1100 Lines: 357 Organization: Men In Black X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1158 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 NNTP-Posting-Host: 203.206.18.25 Message-ID: <3fcf3ebf@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1070546623 203.206.18.25 (4 Dec 2003 06:03:43 -0700) Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail