0

I have a c++ dll function that i want to run inside the C# thread.

Some times I need to cancel that thread, and here is the issue :

Thread.Abort() is evil from the multitude of articles I've read on the topic

The only way to do that was to use a bool and check it's value periodically.

My problem that even i set this value to true it didn't change and still equal to false in c++ code. However when I show a MessageBox that value changed and it works fine. Any ideas why that value changed only when the MessageBox showed and please tell me how to fix that issue. C#

 public void AbortMesh()
        { 
            if (currMeshStruct.Value.MeshThread != null && currMeshStruct.Value.MeshThread.IsAlive)
            {
             //here is my c++ Object and cancel mesh used to set bool to true;                   
             MeshCreator.CancelMesh();
            }
        }

C++

STDMETHODIMP MeshCreator::CancelMesh(void)
{
    this->m_StopMesh = TRUE;
    return S_OK;
}

when I test the boolean value

if (m_StopMesh)
    return S_FALSE;

The value here is always false even i call AbortMesh()

if (m_StopMesh)
        return S_FALSE;

 MessageBox(NULL,aMessage,L"Test",NULL);

 if (m_StopMesh) // here the value is changed to true 
        return S_FALSE;
MRebai
  • 5,344
  • 3
  • 33
  • 52
  • " I launched the c++ *process* using a thread and it worked fine." and "it still equal to false in c++ code" looks strange in one statement. If it is indeed process how you expect local variable to magically cross process boundaries? Anyway you need to add code that shows the problem - not possible to guess without it. – Alexei Levenkov Jun 27 '14 at 16:43
  • Also, `Thread.Abort()` will abort a thread, not a process. It sounds like your C++ code is running in a separate process. `Thread.Abort()` will not terminate that process. – Michael Gunter Jun 27 '14 at 16:44
  • Is it a separate c++ application you launch? Or is it a c++ dll function that you run inside the C# thread? – Eugene Podskal Jun 27 '14 at 16:46
  • 1
    @moez:If you are looking to kill the thread,you can use ManualResetEvent and communicate to thread that you are aborting it.May be you can look at this http://msdn.microsoft.com/en-us/library/ee191552.aspx – Rangesh Jun 27 '14 at 16:51
  • @EugenePodskal it s a c++ dll function that you run inside the C# thread – MRebai Jun 27 '14 at 16:53
  • Are you using C++/CLI? Or what? Show your MeshCreator class's definition and the code that launches the thread. – Eugene Podskal Jun 27 '14 at 17:03
  • it's C++/CLI and it's a big code – MRebai Jun 27 '14 at 17:11
  • Sounds like a race condition. You probably have to use a atomic bool. – MikeMB Jun 27 '14 at 17:33

3 Answers3

3

The non-deterministic thread abortion (like with Thread.Abort) is a really bad practice. The problem is that it is the only practice that allows you to stop your job when job does not know that it could be stopped.

There is no library or framework in .NET I know of that allows to write threaded code that could allow you to run an arbitrary task and abort it at any time without dire consequences.

So, you was completely write when you decided to use manual abort using some synchronization technique.

Solutions:

1) The simplest one is using of a volatile Boolean variable as it was already suggested:

C#

public void AbortMesh()
        { 
            if (currMeshStruct.Value.MeshThread != null && currMeshStruct.Value.MeshThread.IsAlive)
            {                
                MeshCreator.CancelMesh();
            }
        }

C++/CLI

public ref class MeshCreator
{

    private:
        volatile System::Boolean m_StopMesh;
    ...
}

STDMETHODIMP MeshCreator::CancelMesh(void)
{
    this->m_StopMesh = TRUE;
    return S_OK;
}

void MeshCreator::ProcessMesh(void)
{
    Int32 processedParts = 0;

    while(processedParts != totalPartsToProcess)
    {
        ContinueProcessing(processedParts);
        processedParts++;

        if (this->m_StopMesh)
        {
            this->MakeCleanup();
            MessageBox(NULL,aMessage,L"Test",NULL);
        }      
    }

}

Such code should not require any synchronization if you do not make any assumptions on completion of thread after the CancelMesh call - it is not instantaneous and may take variable amount of time to happen.

I don't know why the use of the volatile didn't help you, but there are few moments you could check:

  1. Are you sure that the MeshCreator.CancelMesh(); method call actually happen?
  2. Are you sure that m_StopMesh is properly initialized before the actual processing begins?
  3. Are you sure that you check the variable inside the ProcessMesh often enough to have decent response time from your worker and not expecting something instantaneous?

2)Also if you use .NET 4 or higher you could also try to use the CancellationToken-CancellationTokenSource model. It was initially designed to work with Tasks model but works well with standard threads. It won't really simplify your code but taking into an account the async nature of your processing code will possibly simplify future integration with TPL

 CancellationTokenSource cancTokenSource = new CancellationTokenSource();
 CancellationToken cancToken = cancTokenSource.Token;

 Thread thread = new Thread(() =>
 {
     Int32 iteration = 0;
     while (true)
     {
         Console.WriteLine("Iteration {0}", iteration);
         iteration++;
         Thread.Sleep(1000);
         if (cancToken.IsCancellationRequested)
             break;
      }
  });

  thread.Start();

  Console.WriteLine("Press any key to cancel...");
  Console.ReadKey();
  cancTokenSource.Cancel();

3) You may want to read about interlocked class,monitor locks, autoresetevents and other synchronization, but they are not actually needed in this application

EDIT:

Well, I don't know how it couldn't help(it is not the best idea, but should work for such a scenario), so I'll try later to mock your app and check the issue - possibly it has something to do with how MSVC and CSC handle volatile specifier.

For now try to use Interlocked reads and writes in your app:

public ref class MeshCreator
{

    private:
        System::Boolean m_StopMesh;
    ...
}

STDMETHODIMP MeshCreator::CancelMesh(void)
{
    Interlocked::Exchange(%(this->m_StopMesh), true);
    return S_OK;
}

void MeshCreator::ProcessMesh(void)
{
    Int32 processedParts = 0;

    while(processedParts != totalPartsToProcess)
    {
        ContinueProcessing(processedParts);
        processedParts++;

        if (Interlocked::Read(%(this->m_StopMesh))
        {
            this->MakeCleanup();
            MessageBox(NULL,aMessage,L"Test",NULL);
        }      
    }

}

P.S.: Can you post the code that actually processes the data and checks the variable(I don't mean your full meshes calculations method, just its main stages and elements)?

EDIT: AT LEAST IT'S CLEAR WHAT THE SYSTEM IS ABOUT

It is possible that your child processes are just not exterminated quick enough. Read this SO thread about process killing.

P.S.: And edit your question to more clearly describe your system and problem. It is difficult to get the right answer to a wrong or incomplete question.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • Thanks for your answer, but the only thing that i cannot understand why the m_stopMesh value changed only when i show a messagebox, is the messagebox represent a kind of trigger, or event to change that value. that's really weird 4 m – MRebai Jun 27 '14 at 22:50
  • 1
    To deal with cancellation you have to process your data in some sort of a repetition pattern(see my ProcessItem function) - you complete some chunk of the work, check stop flag, and repeat it again... The only thing I can think of(if the volatile specifier works as intended) is that the flag is not changed when you think it should change, and MessageBox, that blocks the worker thread gives some time for it to be successfully changed. – Eugene Podskal Jun 28 '14 at 03:42
  • I used what you suggest but in vain me to i don't know how the volatile couldnt fix the problem – MRebai Jun 30 '14 at 07:47
  • Hey mate i added some code at the cancelmesh() that allowed me to see when that method is called and i found that's it's called only after a messagebox or when i run another executable inside my mesh process. Is there a way how to force that method to be called inside my thread – MRebai Jun 30 '14 at 09:09
  • I am a bit baffled with 'run another executable inside my mesh process', you mean another **thread** or I have some very wrong understanding of your project - are you using thread or processes, because you've said that you're using thread earlier? And the current Cancel method isn't designed to be called inside your worker thread(that's SynchronizationContext related feature) - it is just designed that it could be called from any thread and impact the execution of your worker thread. – Eugene Podskal Jun 30 '14 at 09:17
  • ok i have a mesh thread and inside that thread im doing some work and after some steps i have an exxutable to run inside that thread that's what i mean – MRebai Jun 30 '14 at 09:21
  • Executable is another program, isn't it? Or are you just refererring to your processing method that runs on the thread in the same App? – Eugene Podskal Jun 30 '14 at 09:23
  • no it's another program, but it runs inside the mesh thread, So the problem is that the cancel method is called only after some times is there how to fix that issue – MRebai Jun 30 '14 at 09:26
  • Plz try to answer today i m really stacked here – MRebai Jun 30 '14 at 09:35
  • So you have one C# app that launches the thread that launches with Process.Start() another C++\CLI application (.exe) file, or what? Your whole system consists of **ONE EXE FILE** or **TWO EXE FILES**? – Eugene Podskal Jun 30 '14 at 09:37
  • i have a C# application which launche a thread (Mesh) there is some calcul inside it, after that inside that mesh thread there is an other exe, after the excution of that exe the mesh thread continue it work and end automaically, whay i need is to make end this thread whenever i want using that cancel method which i found that it's called after some times from the click – MRebai Jun 30 '14 at 09:44
  • Can you include your code that creates the thread, launches two other apps, waits for their completion and aborts them? Because otherwise I'm not sure even what I should look for. – Eugene Podskal Jun 30 '14 at 14:52
1

I launched the c++ process using a thread and it worked fine.

If you want to communicate across process boundaries, you will need to use some sort of cross-process communication.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx

I find Named Pipes convenient and easy to use.

UPDATE

Your comment clarifies that the C++ code is running in-process.

I would suggest a ManualResetEvent. For a great overview of thread synchronization (and threads in general) check out http://www.albahari.com/threading/

Eric J.
  • 147,927
  • 63
  • 340
  • 553
1

Try putting volatile before the field m_StopMesh:

volatile BOOL m_StopMesh;
weston
  • 54,145
  • 21
  • 145
  • 203