温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++多线程怎样进行强制终止

发布时间:2021-09-26 13:43:16 来源:亿速云 阅读:293 作者:柒染 栏目:开发技术

今天就跟大家聊聊有关C++多线程怎样进行强制终止,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

    前言:

    故事的起因来源于我在优化他人c++源码的时候,想通过多线程的方式提升程序的运算效率,主要存在以下需求和难点:

    • 多个线程并行跑模型,看哪个模型跑的快,跑出来后结束其他线程,线程间独立运行无通信过程

    • 源码模型很复杂,函数调用较多,不好改动,因此不太适合通过信号或标志进行通信终止

    线程结束的几种方式:

    线程函数的return返回(建议):这种退出线程的方式是最安全的,在线程函数return返回后, 会清理函数内申请的类对象, 即调用这些对象的析构函数.。然后会自动调用 _endthreadex()函数来清理 _beginthreadex()函数申请的资源(主要是创建的tiddata对象)。
    同一个进程或另一个进程中的线程调用TerminateThread函数(应避免使用该方法):TerminateThread能够撤消任何线程,其中hThread参数用于标识被终止运行的线程的句柄。当线程终止运行时,它的退出代码成为你作为dwExitCode参数传递的值。同时,线程的内核对象的使用计数也被递减。注意TerminateThread函数是异步运行的函数,也就是说,它告诉系统你想要线程终止运行,但是,当函数返回时,不能保证线程被撤消。如果需要确切地知道该线程已经终止运行,必须调用WaitForSingleObject或者类似的函数,传递线程的句柄。
    通过调用ExitThread函数:线程将自行撤消(最好不使用该方法)。该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++类对象)将不被析构。
    ExitProcess和TerminateProcess函数也可以用来终止线程的运行(应避免使用该方法):
    选项2和3可能会导致内存泄漏,实际上,没有任何语言或操作系统可以为你提供异步突然终止线程的便利,且不会警告你不要使用它们。所有这些执行环境都强烈建议开发人员,甚至要求在协作或同步线程终止的基础上构建多线程应用程序。

    现有的线程结束函数,包括linux系统的pthread.h中的pthread_exit()pthread_cancel(),windows系统的win32.h中的ExitThread()TerminateThread(),也就是说,C++没有提供kill掉某个线程的能力,只能被动地等待某个线程的自然结束,析构函数~thread()也不能停止线程,析构函数只能在线程静止时终止线程joinable,对于连接/分离的线程,析构函数根本无法终止线程。

    要终止与OS /编译器相关的函数的线程,我们需要知道如何从C++获取本机线程数据类型std::thread。幸运的是,在调用或之前std::thread提供了一个API native_handle()以获取线程的本机句柄类型。并且可以将此本地句柄传递给本地OS线程终止函数,例如join() detach() pthread_cancel()。

    以下代码用于显示std::thread::native_handle()std::thread::get_id()pthread_self()返回相同的代码pthread_t来处理Linux / GCC的C++线程

    #include <mutex>
    #include <iostream>
    #include <chrono>
    #include <cstring>
    #include <pthread.h>
     
    std::mutex iomutex;
    void f(int num)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::lock_guard<std::mutex> lk(iomutex);
        std::cout << "Thread " << num << " pthread_t " << pthread_self() << std::endl;
    }
     
    int main()
    {
        std::thread t1(f, 1), t2(f, 2);
        
        //t1.join(); t2.join();  ----------------pos 1
        //t1.detach(); t2.detach(); -------------pos 2
        
        std::cout << "Thread 1 thread id " << t1.get_id() << std::endl;
        std::cout << "Thread 2 thread id " << t2.get_id() << std::endl;
        
        std::cout << "Thread 1 native handle " << t1.native_handle() << std::endl;
        std::cout << "Thread 2 native handle " << t2.native_handle() << std::endl;
        
        t1.join(); t2.join();
        //t1.detach(); t2.detach();
    }

    运行后可以得到结果

    $ g++ -Wall -std=c++11 cpp_thread_pthread.cc -o cpp_thread_pthread -pthread -lpthread
    $ ./cpp_thread_pthread
    Thread 1 thread id 140109390030592
    Thread 2 thread id 140109381637888
    Thread 1 native handle 140109390030592
    Thread 2 native handle 140109381637888
    Thread 1 pthread_t 140109390030592
    Thread 2 pthread_t 140109381637888

    uncommentpos 1或者pos 2后,即调用join()或之后detach(),C++线程会丢失本机句柄类型的信息

    $ ./cpp_thread_pthread
    Thread 1 pthread_t 139811504355072
    Thread 2 pthread_t 139811495962368
    Thread 1 thread id thread::id of a non-executing thread
    Thread 2 thread id thread::id of a non-executing thread
    Thread 1 native handle 0
    Thread 2 native handle 0

    因此,要有效地调用本机线程终止函数(例如pthread_cancel),需要在调用std::thread::join()时或之前保存本机句柄std::thread::detach()。这样,始终可以使用有效的本机句柄终止线程。

    class Foo {
    public:
        void sleep_for(const std::string &tname, int num)
        {
            prctl(PR_SET_NAME,tname.c_str(),0,0,0);        
            sleep(num);
        }
    
        void start_thread(const std::string &tname)
        {
            std::thread thrd = std::thread(&Foo::sleep_for, this, tname, 3600);
            tm_[tname] = thrd.native_handle();
            thrd.detach();
            std::cout << "Thread " << tname << " created:" << std::endl;
        }
    
        void stop_thread(const std::string &tname)
        {
            ThreadMap::const_iterator it = tm_.find(tname);
            if (it != tm_.end()) {
                pthread_cancel(it->second);
                tm_.erase(tname);
                std::cout << "Thread " << tname << " killed:" << std::endl;
            }
        }
    
    private:
        typedef std::unordered_map<std::string, pthread_t> ThreadMap;
        ThreadMap tm_;
    };
    
    int main()
    {
        Foo foo;
        std::string keyword("test_thread");
        std::string tname1 = keyword + "1";
        std::string tname2 = keyword + "2";
    
        // create and kill thread 1
        foo.start_thread(tname1);
        foo.stop_thread(tname1);
    
        // create and kill thread 2
        foo.start_thread(tname2);
        foo.stop_thread(tname2);
    
        return 0;
    }

    结果是:

    $ g++ -Wall -std=c++11 kill_cpp_thread.cc -o kill_cpp_thread -pthread -lpthread
    $ ./kill_cpp_thread
    Thread test_thread1 created:
    30332 30333 pts/5    00:00:00 test_thread1
    Thread test_thread1 killed:
    Thread test_thread2 created:
    30332 30340 pts/5    00:00:00 test_thread2
    Thread test_thread2 killed:

    当然,条件允许的话最好还是使用返回或信号的方式终止线程,这样也符合安全可信的要求。

    看完上述内容,你们对C++多线程怎样进行强制终止有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI