当前位置: 首页 > news >正文

【C】线程控制

创建线程

#include <pthread.h>int pthread_create(pthread_t * thread,const pthread_attr_t * attr,void *(*start_routine)(void*), void * arg);

返回值:成功返回0,失败返回错误号。

thread:成功返回后,新创建的线程的id被填写到 thread参数所指向的内存单元。线程id的类型是pthread_t,它只在当前进程中保证是唯一的,在不同的系统中pthread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self()可以获取当前线程地id。

attr:表示线程属性,这里暂不讨论。

start_routine和arg:新线程所指向的代码由函数指针start_routine决定。start_routine函数接收一个参数arg,该参数的类型为void *,这个指针按什么类型解释由调用者自己定义,start_routine的返回值类型也是void *,这个指针的函数的含义同样由调用者自己定义。

#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>static void thread_func(const char *arg)
{printf("arg=%s\n", arg);pthread_t tid = pthread_self();printf("new thread pid=%u\n", (uint32_t)tid);
}int main(void)
{pthread_t id;int ret = pthread_create(&id, NULL, thread_func, "i am iron man");if (0 != ret){printf("pthread_carete error=%s", strerror(ret));}printf("new thread pid=%u\n", (uint32_t)id);while (1){usleep(1000);}return 0;
}

输出结果为:

new thread pid=1
arg=i am iron man
new thread pid=1

可知,在window上,thread_t类型是一个整型值。

终止线程

如果需要终止某个线程而不终止整个进程,可以有三种方法:

  • 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit
  • 一个线程可以调用pthread_cancel终止同一进程中地另一个线程。
  • 线程可以调用pthread_exit终止自己。

在介绍终止之前,我们先介绍一下pthread_join函数。

#include <pthread.h>int pthread_join(pthread_t thread, void **value_ptr);//返回值:成功返回0,失败返回错误号。

调用该函数地线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态时不同的,总结如下:

  • 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
  • 如果thread线程被别的线程调用thread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED
  • 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元里存放的是传给pthread_exit的参数。

如果对thread线程的终止状态不感兴趣,可以传NULLvalue_ptr参数。

一般情况下,线程终止后,其终止状态一直保留到其他线程调用pthread_join获取它的状态为止。但是线程也可以被设置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。对一个尚未detach的线程调用pthread_joinpthread_detach都可以把该线程设置为detach状态,也就是说,不能对同一线程调用两次pthread_join,或者如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

#include <pthread.h>int pthread_detach(pthread_t tid);//返回值:成功返回0,失败返回错误号。
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>static void *thread1_func(const char *arg)
{printf("arg=%s\n", arg);pthread_t tid = pthread_self();printf("new thread pid=%u\n", (uint32_t)tid);return (void *)0xFF;
}static void *thread2_func(const char *arg)
{printf("arg=%s\n", arg);pthread_t tid = pthread_self();printf("new thread pid=%u\n", (uint32_t)tid);pthread_exit((void *)0xFE);
}static void *thread3_func(const char *arg)
{printf("arg=%s\n", arg);pthread_t tid = pthread_self();printf("new thread pid=%u\n", (uint32_t)tid);while (1){printf("%s running\n", arg);usleep(5000 * 100);}
}int main(void)
{pthread_t id1;int ret1 = pthread_create(&id1, NULL, thread1_func, "i am thread1");if (0 != ret1){printf("pthread_carete error=%s", strerror(ret1));}void *thread1_ret;pthread_join(id1, &thread1_ret);printf("thread1_ret=%d\n", (int)thread1_ret);pthread_t id2;int ret2 = pthread_create(&id2, NULL, thread2_func, "i am thread2");if (0 != ret2){printf("pthread_carete error=%s", strerror(ret2));}void *thread2_ret;pthread_join(id2, &thread2_ret);printf("thread2_ret=%d\n", (int)thread2_ret);pthread_t id3;int ret3 = pthread_create(&id3, NULL, thread3_func, "i am thread3");if (0 != ret3){printf("pthread_carete error=%s", strerror(ret3));}void *thread3_ret;sleep(1);pthread_cancel(id3);pthread_join(id3, &thread3_ret);printf("thread3_ret=%d\n", (int)thread3_ret);while (1){usleep(1000);}return 0;
}

输出为:

arg=i am thread1
new thread pid=1
thread1_ret=255
arg=i am thread2
new thread pid=3
thread2_ret=254
arg=i am thread3
new thread pid=4
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running

我们可以看到,线程1和线程2的终止与我们的预期一样,但是线程3使用pthread_cancel()似乎没有真正终止线程。那这里就需要引用另外两个概念了。

线程终止状态
	@state:PTHREAD_CANCEL_ENABLE:线程对cancel信号立即有反应,将设置为CANCEL状态 (默认)PTHREAD_CANCEL_DISABLE:如果线程state为不可取消,线程不理会信号,继续执行,而使用cancel函数的线程会一直阻塞到可取消状态@oldstate:NULL:state写入有效,即当前只想设置属性,而不关心原来的属性不为NULL:state不写入,保持原有的设定,且获取原来的属性return:成功返回0,错误返回errno	EINVAL:无效的stateint pthread_setcancelstate(int state,int *oldstate)
线程终止类型
	@type:PTHREAD_CANCEL_DEFERRED:运行到下一个取消点就退出 (默认)PTHREAD_CANCEL_ASYNCHRONOUS:直接退出@oldtyoe:NULL:type写入有效,即当前只想设置属性,而不关心原来的属性不为NULL:type不写入,保持原有的设定,且获取原来的属性return:成功返回0,错误返回errno	EINVAL:无效的type
int pthread_setcanceltype(int type,int *oldtype)

所以,如下想要使用pthread_cancel终止线程,那么我们必须在线程函数中调用

pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

当我们把线程函数改成:

static void *thread3_func(const char *arg)
{pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);printf("arg=%s\n", arg);pthread_t tid = pthread_self();printf("new thread pid=%u\n", (uint32_t)tid);while (1){printf("%s running\n", arg);usleep(5000 * 100);}
}

那么就可以正常终止了,输出结果如下:

arg=i am thread1
new thread pid=1
thread1_ret=255
arg=i am thread2
new thread pid=3
thread2_ret=254
arg=i am thread3
new thread pid=4
i am thread3 running
i am thread3 running
thread3_ret=-559038737
http://www.lryc.cn/news/23737.html

相关文章:

  • Maven工程打jar包的N种方式
  • 一文了解GPU并行计算CUDA
  • 全网资料最全Java数据结构与算法(1)
  • 【项目实战】SpringMVC拦截器HandlerInterceptor入门介绍
  • 阿里淘宝新势力造型合伙人P8、年薪百万的欧阳娜娜也躲不过的魔鬼面试,看的我心服口服
  • 深度学习笔记:不同的反向传播迭代方法
  • ElasticSearch 学习笔记总结(三)
  • 深入理解border以及应用
  • 如何复现论文?什么是论文复现?
  • 22.2.28打卡 Codeforces Round #851 (Div. 2) A~C
  • Learining C++ No.12【vector】
  • 【数电基础】——逻辑代数运算
  • 【Redis】什么是缓存与数据库双写不一致?怎么解决?
  • 互联网衰退期,测试工程师35岁之路怎么走...
  • 动态规划(以背包问题为例)
  • Java异常
  • 别克GL8改装完工,一起来看看效果
  • mac 中 shell 一些知识
  • CentOS 配置FTP(开启VSFTPD服务)
  • Http的请求方法
  • Python字典-- 内附蓝桥题:统计数字
  • 文本处理工具
  • C++STL详解(三)——vector的介绍和使用
  • GEBCO海洋数据下载
  • 【C++容器】vector、map、hash_map、unordered_map四大容器的性能分析【2023.02.28】
  • ACM-蓝桥杯训练第一周
  • python基础—字符串操作
  • 【Spring】通过JdbcTemplate实现CRUD操作
  • 实战|掌握Linux内存监视:free命令详解与使用技巧
  • 嵌入式入门必看!调试工具安装——基于 AM64x核心板