🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #12450

Re: Killing off a crashed thread

#12450
From: Rodolfo Frino
Date: Thu, 04 Dec 2003 14:03
355 lines
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-mail
References: <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