Abort Thread through another process in C #

5

I'm developing an application in ASP.Net 5.0, where it needs to start a task through a% Secondary% co, as in the example below:

//Inicia processo de pesquisa            
var ppBlo = new ProcessoPesquisaBLO();

//Cria a Thread para rodar o processo
Thread tProcesso = new Thread(ppBlo.IniciarPesquisa);
tProcesso.Priority = ThreadPriority.Highest;
tProcesso.Start();

This implementation is within a function that can be triggered by different users at different times, because it is a Web application.

However, in a second screen it has the listing of all Thread . And the user can stop the execution at any time.

In addition to having a concurrent Threads limit that the user can have.

Doubt

Precious in some way to abort the Threads that are running (since the user can quit at any time). And the function that will do this procedure does not have access to the attributes of the function class from where the Threads are created.

I do not know if it's useful for anything, but I'm storing the value of the Threads attribute of every ManagedThreadId created in the database.

    
asked by anonymous 22.11.2016 / 19:09

2 answers

3

In .Net, threads are automatically recycled when they are finished. The only thing you have to ensure is that threads end up as fast as possible. There is also no easy way to get all the managed threads associated with a process, so you should save the threads you create in a list.

private static readonly List<Thread> _threads = new List<Thread>();

Thread tProcesso = new Thread(ppBlo.IniciarPesquisa);
tProcesso.Priority = ThreadPriority.Highest;
tProcesso.Start();
_threads.Add(tProcesso);

Now you can interrupt the threads

The idea is that you interrupt the thread, so that it exits with ThreadInterruptedException .

For this you have to call the Interrupt method of the thread.

//procure as threads do usuario aqui
var threads = _threads.where(t => t.ManagedThreadId == 1);
foreach(var thread in threads){
    thread.Interrupt();
    _threads.Remove(thread); //lembre-se de apagar a thread da lista
}
Note that if threads never enter a blocking condition like Thread.Sleep , WaitForSingleObject (like Mutex.WaitOne ), Thread.Join , this exception will never happen (this only happens if the thread is 100% processor).

As suggested in the comments by @FBatista the very same was to have used a mechanism that would allow cancellation as the task.

I explained in this question how cancellation can be done

    
28.11.2016 / 17:37
2

Well, the first thing you need is already doing, which is to save the ManagedThreadId .

For the user to abort, you also need to save the list to show only his, but that's not what the question is about.

The first step is to import the kernel32.dll DLL and use it to open and terminate the Thread with ManagedThreadId . It would look like this:

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);


    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);

After this, just terminate the selected Thread, like this:

        IntPtr ptrThread = OpenThread(1, false, (uint)id);
        TerminateThread(ptrThread, 1);

See a complete example in the code below:

class Program
{

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);


    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);


    static void Main(string[] args)
    {
        Console.Out.WriteLine("Forking off threads...");
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(new ThreadStart(RunInfinite));
            Console.Out.WriteLine("Thread " + t.Name + "(ManagedThreadId: " + t.ManagedThreadId + ") created!");
        }


        ProcessThreadCollection processThreads = Process.GetCurrentProcess().Threads;
        Console.Out.WriteLine("=> Total threads: " + processThreads.Count);
        foreach (ProcessThread pt in processThreads)
        {
            int timerSeconds = 5;
            while (timerSeconds-- > 0)
            {
                Console.Out.Write("\r Seconds before thread " + pt.Id + " dies: " + timerSeconds);
                System.Threading.Thread.Sleep(1000);
            }


            IntPtr ptrThread = OpenThread(1, false, (uint)pt.Id);
            if (AppDomain.GetCurrentThreadId() != pt.Id)
            {
                try
                {
                    TerminateThread(ptrThread, 1);
                    Console.Out.Write(". Thread killed.\n");
                }
                catch (Exception e)
                {
                    Console.Out.WriteLine(e.ToString());
                }
            }
            else
                Console.Out.Write(". Not killing... It's the current thread!\n");


        }
        Console.Out.WriteLine("=> Total threads now: " + Process.GetCurrentProcess().Threads.Count);
        Console.ReadLine();
    }




    public static void RunInfinite()
    {
        while (true)
        {
            System.Threading.Thread.Sleep(10000);
        }
    }
}

Another way would be to this answer , where you would look up Threads and check if the id is the same, but this way I would not advise you much, because of what you said, you will have many Threads in your system.

public void KillThread(int index)
    {
        string id = string.Format("MyThread{0}",index);
        foreach (Thread thread in _threads)
        {
            if (thread.Name == id)
                thread.Abort();
        }
    }

References:

28.11.2016 / 13:08