Сначала вы должны согласовать метод завершения потока. Например, значение running_ valiable, которое поток может проверить и выполнить.
Код основного потока должен быть заключен в блок исключения, который перехватывает и ThreadInterruptException, и ThreadAbortException, которые будут аккуратно приводить в порядок поток при выходе.
В случае ThreadInterruptException вы можете проверить переменную running_, чтобы увидеть, следует ли вам продолжить. В случае ThreadAbortException вы должны немедленно привести в порядок и выйти из процедуры потока.
Код, который пытается остановить поток, должен сделать следующее:
running_ = false;
threadInstance_.Interrupt();
if(!threadInstance_.Join(2000)) { // or an agreed resonable time
threadInstance_.Abort();
}