基本线程的动作

继续之前C语言线程的文章:文章1 文章2 来了解基本的线程操作。

设置线程属性

设置脱离状态

下面代码中关键的地方在于:

  • 通过 res = pthread_attr_init(&thread_attr); 初始化一个线程属性
  • 通过 res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); 将属性设置为脱离状态(PTHREAD_CREATE_DETACHED),即不能通过调用 pthread_join 来获得另一个线程的退出状态
  • 另外还有一个常用的默认状态是 PTHREAD_CREATE_JOINABLE ,可以允许两个线程重新合并。
  • 属性用完后对其进行清理回收 (void)pthread_attr_destroy(&thread_attr);
  • 通过共享的变量 thread_finished 来检测子线程是否已经结束

代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h> void *thread_function(void *arg); char message[] = "Hello World";
int thread_finished = 0; int main() {
int res;
pthread_t a_thread; pthread_attr_t thread_attr; res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
(void)pthread_attr_destroy(&thread_attr);
while(!thread_finished) {
printf("Waiting for thread to say it's finished...\n");
sleep(1);
}
printf("Other thread finished, bye!\n");
exit(EXIT_SUCCESS);
} void *thread_function(void *arg){
printf("thread_function is running. Argument was %s\n", (char *)arg);
sleep(4);
printf("Second thread setting finished flag, and exiting now\n");
thread_finished = 1;
pthread_exit(NULL);
}

设置调度属性

线程库提供以下调度策略:

| SCHED_FIFO  | 先进先出 (FIFO) 调度。每个线程都有一个固定的优先级;当多个线程具有相同的优先级时,它们按照先进先出 (FIFO) 的顺序运行直到完成 |
| SCHED_RR | 循环 (RR) 调度。每个线程都有固定的优先级;当多个线程具有相同的优先级时,它们按照先进先出 (FIFO) 的顺序在一个 固定的时间片内运行。 |
| SCHED_OTHER | 缺省的 AIX® 调度。每个线程都有一个由调度程序根据线程的活动动态修改的初始优先级;线程的执行是按时间分割的。在其他系统上,这个调度策略可能会不同。 |

设置调度属性和设置很相似:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h> void *thread_function(void *arg); char message[] = "Hello World";
int thread_finished = 0; int main() {
int res;
pthread_t a_thread;
pthread_attr_t thread_attr; int max_priority;
int min_priority;
struct sched_param scheduling_value; res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setschedpolicy(&thread_attr, SCHED_OTHER);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
max_priority = sched_get_priority_max(SCHED_OTHER);
min_priority = sched_get_priority_min(SCHED_OTHER);
scheduling_value.sched_priority = min_priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
(void)pthread_attr_destroy(&thread_attr);
while(!thread_finished) {
printf("Waiting for thread to say it's finished...\n");
sleep(1);
}
printf("Other thread finished, bye!\n");
exit(EXIT_SUCCESS);
} void *thread_function(void *arg) {
printf("thread_function is running. Argument was %s\n", (char *)arg);
sleep(4);
printf("Second thread setting finished flag, and exiting now\n");
thread_finished = 1;
pthread_exit(NULL);
}

取消线程

  • 通过 int pthread_cancel(pthread_t thread); 来请求一个线程终止
  • 通过 int pthread_setcancelstate(int state, int *oldstate) 来设置接受的进程是允许取消请求还是忽略它
  • 通过 int pthread_setcanceltype(int type, int *oldtype) 来设置取消类型, PTHREAD_CANCEL_ASYCHRONOUS 代表接收到取消请求后立即行动, THREAD_CANCEL_DEFERRED 表示在接收到请求后,等待函数执行下述动作之一后才取消线程: pthread_join, pthread_cond_wait, pthread_cond_timeout, pthread_test_cancel, sem_wait, sigwait

代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h> void *thread_function(void *arg); int main () {
int res;
pthread_t a_thread;
void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0){
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep(3);
printf("Caceling thread...\n");
res = pthread_cancel(a_thread);
if (res != 0){
perror("Thread cancelation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} void *thread_function(void *arg) {
int i, res;
res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (res != 0) {
perror("Thread pthread_setcalcelstate failed");
exit(EXIT_FAILURE);
}
res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
if (res != 0) {
perror("Thread pthread_setcanceltype failed");
exit(EXIT_FAILURE);
}
printf("thread_function is running\n");
for(i=0; i<10; i++) {
printf("Thread is still running (%d)...\n", i);
sleep(1);
}
pthread_exit(0);
}

主线程创建多个线程示例

代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h> #define NUM_THREADS 6 void *thread_function(void *arg); int main() {
int res;
pthread_t a_thread[NUM_THREADS];
void *thread_result;
int lots_of_threads; for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) { res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)&lots_of_threads);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep(1);
}
printf("Waiting for threads to finish...\n");
for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
res = pthread_join(a_thread[lots_of_threads], &thread_result);
if (res == 0) {
printf("Picked up a thread\n");
}
else {
perror("pthread_join failed");
}
}
printf("All done\n");
exit(EXIT_SUCCESS);
} void *thread_function(void *arg) {
int my_number = *(int *)arg;
int rand_num; printf("thread_function is running. Argument was %d\n", my_number);
rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));
sleep(rand_num);
printf("Bye from %d\n", my_number);
pthread_exit(NULL);
}

运行结果如下:

thread_function is running. Argument was 0
Bye from 0
thread_function is running. Argument was 1
thread_function is running. Argument was 2
Bye from 1
thread_function is running. Argument was 3
thread_function is running. Argument was 4
thread_function is running. Argument was 5
Waiting for threads to finish...
Bye from 5
Picked up a thread
Bye from 3
Bye from 2
Bye from 4
Picked up a thread
Picked up a thread
Picked up a thread
Picked up a thread
Picked up a thread
All done

了解更多

参考资料

PS

不得不承认,我失败了。曾计划每天分享一篇python相关知识点但没有做到。失败的原因想找可以找很多比如最近在做一个小的项目、这几天出去聚会没有时间、工作出现问题加班到比较晚等等,然而总结起来不外乎在心里它的重要程度是怎么样的。我反思了下几乎做到一天一篇的这一个月过程做出改变,不再要求一天一篇,而是当我有好的素材要分享时才分享,这样与我与大家都是一件好事,我可以动态调度自己的精力和注意力,比如最近实现了一半的一个odoo项目依赖关系分析器可以尽快把它做完,对于读者来说也可以减少干扰看到更好的分享而不是像我之前有几篇那样划水的。但每周应该会有3-4篇Python的知识可以分享。另外我目前的工作是基于Odoo的,我计划尝试做一些基础的教程来分享这个我熟悉的框架,如果有进展一定会告知感兴趣的读者。感谢读者。

最后向漩涡鸣人致敬,朝他的“说到做到,这就是我的忍道”努力。

理解线程3 c语言示例线程基本操作的更多相关文章

  1. 加深对AQS原理的理解示例二:自己设计一个同步工具,同一时刻最多只有两个线程能访问,超过线程将被阻塞

    /** *@Desc 设计一个同步工具,同一时刻最多只有两个线程能访问,超过线程将被阻塞<br> * 思路分析: * 1.共享锁 两个线程及以内能成功获取到锁 * 2. *@Author ...

  2. 深入理解Java类加载器(二):线程上下文类加载器

    摘要: 博文<深入理解Java类加载器(一):Java类加载原理解析>提到的类加载器的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器的实现方式.在Java ...

  3. 深入理解java虚拟机-第13章-线程安全与锁优化

    第十三章 线程安全与锁优化 线程安全 java语言中的线程安全 1 不可变.Immutable 的对象一定是线程安全的 2 绝对线程安全 一个类要达到不管运行时环境如何,调用者都不需要额外的同步措施, ...

  4. android线程 Handler Message Queue AsyncTask线程模型 线程交互 + 修改Button样式 示例 最终easy整合版

     首先原谅我把文章的标题写的这么长.其实我还嫌弃它短了因为 写不下去了所以我就不写了.因为我实在不知道该怎么定义这篇文章的标题或许应该叫 "乱谈"比较合适. 这样可能还体现了 ...

  5. 深入理解JVM - Java内存模型与线程 - 第十二章

    Java内存模型 主内存与工作内存 Java内存模型主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.此处的变量(Variable)与Java编程中 ...

  6. 深入理解JVM(③)再谈线程安全

    前言 我们在编写程序的时候,一般是有个顺序的,就是先实现再优化,并不是所有的牛P程序都是一次就写出来的,肯定都是不断的优化完善来持续实现的.因此我们在考虑实现高并发程序的时候,要先保证并发的正确性,然 ...

  7. 理解微信小程序的双线程模型

    有过微信小程序开发经验的朋友应该都知道"双线程模型"这个概念,本文简单梳理一下双线程模型的一些科普知识,学识浅薄,若有错误欢迎指正. 我以前就职于「小程序·云开发」团队,在对外的一 ...

  8. 深入理解java虚拟机(7)---线程安全 & 锁优化

    关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...

  9. go语言实现线程池

    话说真的好久没有写博客了,最近赶新项目,工作太忙了.这一周任务比较少,又可以随便敲敲了. 逛论坛的时候突发奇想,想用go语言实现一个线程池,主要功能是:添加total个任务到线程池中,线程池开启num ...

随机推荐

  1. sharepoint2007就地升级2010系列(二)环境概述及升级前准备

    环境介绍:1台2GB的虚机 现在是windows server 2008 sp2 X64 +SQL 2005+SQL2005 sp3+sharepoint2007+sharepoint2007SP2 ...

  2. Maven 私有库和本地库的安装与配置 Sonatype Nexus + Maven

    环境:CentOS 7.0 Final.JDK8.Sonatype Nexus.Maven 虚拟机模拟IP:192.168.16.167 备注:root权限用户操作 前提:已安装 JDK8 并配置好了 ...

  3. SAP ECC6.0-中建信息版

    平台: SUSE Enterprise Server 类型: 虚拟机镜像 软件包: sap ecc 6.0 ehp7 sps10 commercial erp sap 服务优惠价: 按服务商许可协议 ...

  4. c\c++数据类型存储

    C四个 C++五个 一. 在c中分为这几个存储区 1.栈 - 由编译器自动分配释放 2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 3.全局区(静态区),全局变量和静态变量 ...

  5. 初识Python(四)

    一.数字数据类型 Python的数字数据类型用于存储数值,它是不可变的数据类型,这意味着改变数字数据类型,则需要一个新分配的对象: Python支持四种不同的数值类型: 整型(Int):通常被称为是整 ...

  6. 如何将位置值写入simotion encoder?

    目标: 将变量值(任意实数)写入Encoder,作为encoder的实际位置值.例如,将MP177手轮的值写入编码器,达到SMC30配置手轮的功能. Platform: simotion D435-2 ...

  7. [pytorch] 官网教程+注释

    pytorch官网教程+注释 Classifier import torch import torchvision import torchvision.transforms as transform ...

  8. 2017.9.14 HTML学习总结---超链接标签图片标签

    2.4 超链接标签 定义:它是指从一个对象指向另一个对象的指针,它可以是网页中的一段文字  也可以是一张图片,以实现从一个页面到另一个页面的跳转. 格式:<a href="url&qu ...

  9. openstack kilo 命令行

    把下面内容放到.bashrc中,或者直接执行也行. export OS_USERNAME=adminexport OS_PASSWORD=admin              #根据实际密码来设    ...

  10. 旧文备份:Python国际化支持

    Python通过gettext模块支持国际化(i18n),可以实现程序的多语言界面的支持,下面是我的多语言支持实现: 在python安装目录下的./Tools/i18n/(windows下例 D:\P ...