C语言如何终止线程?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言如何终止线程?相关的知识,希望对你有一定的参考价值。

参考技术A

面只有两个线程,是生产者/消费者模式,已编译通过,注释很详细。

/* 以生产者和消费者模型问题来阐述Linux线程的控制和通信你

生产者线程将生产的产品送入缓冲区,消费者线程则从中取出产品。

缓冲区有N个,是一个环形的缓冲池。

*/

#include <stdio.h>

#include <pthread.h>

#define BUFFER_SIZE 16

struct prodcons

int buffer[BUFFER_SIZE];/*实际存放数据的数组*/

pthread_mutex_t lock;/*互斥体lock,用于对缓冲区的互斥操作*/

int readpos,writepos; /*读写指针*/

pthread_cond_t notempty;/*缓冲区非空的条件变量*/

pthread_cond_t notfull;/*缓冲区未满 的条件变量*/

;

/*初始化缓冲区*/

void pthread_init( struct prodcons *p)

pthread_mutex_init(&p->lock,NULL);

pthread_cond_init(&p->notempty,NULL);

pthread_cond_init(&p->notfull,NULL);

p->readpos = 0;

p->writepos = 0;

/*将产品放入缓冲区,这里是存入一个整数*/

void put(struct prodcons *p,int data)

pthread_mutex_lock(&p->lock);

/*等待缓冲区未满*/

if((p->writepos +1)%BUFFER_SIZE ==p->readpos)

pthread_cond_wait(&p->notfull,&p->lock);

p->buffer[p->writepos] =data;

p->writepos++;

if(p->writepos >= BUFFER_SIZE)

p->writepos = 0;

pthread_cond_signal(&p->notempty);

pthread_mutex_unlock(&p->lock);

/*从缓冲区取出整数*/

int get(struct prodcons *p)

int data;

pthread_mutex_lock(&p->lock);

/*等待缓冲区非空*/

if(p->writepos == p->readpos)

pthread_cond_wait(&p->notempty ,&p->lock);//非空就设置条件变量notempty

/*读书据,移动读指针*/

data = p->buffer[p->readpos];

p->readpos++;

if(p->readpos == BUFFER_SIZE)

p->readpos = 0;

/*设置缓冲区未满的条件变量*/

pthread_cond_signal(&p->notfull);

pthread_mutex_unlock(&p->lock);

return data;

/*测试:生产站线程将1 到1000的整数送入缓冲区,消费者线程从缓冲区中获取整数,两者都打印信息*/

#define OVER (-1)

struct prodcons buffer;

void *producer(void *data)

int n;

for( n=0;n<1000;n++)

printf("%d ------>\\n",n);

put(&buffer,n);

put(&buffer,OVER);

return NULL;

void *consumer(void *data)

int d;

while(1)

d = get(&buffer);

if(d == OVER)

break;

else

printf("----->%d\\n",d);

return NULL;

int main()

pthread_t th_p,th_c;

void *retval;

pthread_init(&buffer);

pthread_create(&th_p,NULL,producer,0);

pthread_create(&th_c,NULL,consumer,0);

/*等待两个线程结束*/

pthread_join(th_p, &retval);

pthread_join(th_c,&retval);

return 0;

C++多线程强制终止

摘要:实际上,没有任何语言或操作系统可以为你提供异步突然终止线程的便利,且不会警告你不要使用它们。

本文分享自华为云社区《如何编写高效、优雅、可信代码系列(1)——C++多线程强制终止》,原文作者:我是一颗大西瓜  。

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

  1. 多个线程并行跑模型,看哪个模型跑的快,跑出来后结束其他线程,线程间独立运行无通信过程
  2. 源码模型很复杂,函数调用较多,不好改动,因此不太适合通过信号或标志进行通信终止

网上搜索了一下线程结束的几种方式:

  1. 线程函数的return返回(建议)。这种退出线程的方式是最安全的,在线程函数return返回后, 会清理函数内申请的类对象, 即调用这些对象的析构函数.。然后会自动调用 _endthreadex()函数来清理 _beginthreadex()函数申请的资源(主要是创建的tiddata对象)。
  2. 同一个进程或另一个进程中的线程调用TerminateThread函数(应避免使用该方法)。TerminateThread能够撤消任何线程,其中hThread参数用于标识被终止运行的线程的句柄。当线程终止运行时,它的退出代码成为你作为dwExitCode参数传递的值。同时,线程的内核对象的使用计数也被递减。注意TerminateThread函数是异步运行的函数,也就是说,它告诉系统你想要线程终止运行,但是,当函数返回时,不能保证线程被撤消。如果需要确切地知道该线程已经终止运行,必须调用WaitForSingleObject或者类似的函数,传递线程的句柄。
  3. 通过调用ExitThread函数,线程将自行撤消(最好不使用该方法)。该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++类对象)将不被析构。
  4. 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语言如何终止线程?的主要内容,如果未能解决你的问题,请参考以下文章

C语言如何终止线程?

C++多线程强制终止

C++多线程强制终止

c语言实现多线程

C语言 pthread_join()函数

c语言中,创建的子线程如何给主线程发消息?