POSIX线程

POSIX线程

标签(空格分隔): Linux程序设计


什么是线程

线程是一个进程内部的一个控制序列。

当在进程中创建一个新线程时,新的执行线程将拥有自己的栈(因此也有自己的局部变量),但与它的创建者共享全局变量、文件描述符、信号处理函数和当前目录状态。

线程的优点:

  1. 让程序看起来好像是在做两件事情;
  2. 一个混杂着输入、计算和输出的应用程序,可以将这几个部分分离成3个线程来执行,从而改善程序执行的性能;
  3. 一般而言,线程之间的切换需要操作系统做的工作比进程之间的切换少的多,因此多个线程对资源的需求要远少于多个进程。

线程创建相关函数

#include<pthread.h>//创建线程
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
//thread: 指向pthread_t类型的指针,用来引用该新线程;
//attr: 用于设置线程的属性,一般为NULL;
//第3,4个参数为线程将要启动执行的函数,以及传递给该函数的参数
//返回:调用成功返回0,失败则返回错误代码//线程等待函数
int pthread_join(pthread_t th, void **thread_return);
//th: 指定将要等待的线程
//thread_return: 指向线程返回值的指针(的指针)。
//返回:成功返回0,失败则返回错误代码//线程终止函数
void pthread_exit(void *retval);
//retval: 指向线程返回值的指针(pthread_join可以获取该指针)

示例:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>void *thread_function(void *arg);
char msg[] = "Hello World";int main()
{int res;pthread_t a_thread;void *thread_result;res = pthread_create(&a_thread, NULL, thread_function, (void *)msg);if(res != 0){perror("Thread creation 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);}printf("Thread joined, it returned %s\n", (char *)thread_result);printf("Message is now %s\n", msg);exit(EXIT_SUCCESS);
}void *thread_function(void *arg)
{printf("Thread function is runing. Argument was %s\n",(char *)arg);sleep(3);strcpy(msg,"Bye!");pthread_exit("Thank you for the CPU time.");
}

线程同步

互斥量mutex

参考:https://docs.oracle.com/cd/E19253-01/819-7051/sync-12/index.html

#include<pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
//mutex: 事先声明过的pthread_mutex_t对象的指针
//mutexattr: 设置互斥量的属性,默认为fast。该参数一般置为NULL
//返回: 成功返回0,失败则返回错误代码//加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

示例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;int main() {int res;pthread_t a_thread;void *thread_result;res = pthread_mutex_init(&work_mutex, NULL);if (res != 0) {perror("Mutex initialization failed");exit(EXIT_FAILURE);}res = pthread_create(&a_thread, NULL, thread_function, NULL);if (res != 0) {perror("Thread creation failed");exit(EXIT_FAILURE);}pthread_mutex_lock(&work_mutex);printf("Input some text. Enter 'end' to finish\n");while(!time_to_exit) {fgets(work_area, WORK_SIZE, stdin);pthread_mutex_unlock(&work_mutex);while(1) {pthread_mutex_lock(&work_mutex);if (work_area[0] != '\0') {pthread_mutex_unlock(&work_mutex);sleep(1);}else {break;}}}pthread_mutex_unlock(&work_mutex);printf("\nWaiting for thread to finish...\n");res = pthread_join(a_thread, &thread_result);if (res != 0) {perror("Thread join failed");exit(EXIT_FAILURE);}printf("Thread joined\n");pthread_mutex_destroy(&work_mutex);exit(EXIT_SUCCESS);
}void *thread_function(void *arg) {sleep(1);pthread_mutex_lock(&work_mutex);while(strncmp("end", work_area, 3) != 0) {printf("You input %d characters\n", strlen(work_area) -1);work_area[0] = '\0';pthread_mutex_unlock(&work_mutex);sleep(1);pthread_mutex_lock(&work_mutex);while (work_area[0] == '\0' ) {pthread_mutex_unlock(&work_mutex);sleep(1);pthread_mutex_lock(&work_mutex);}}time_to_exit = 1;work_area[0] = '\0';pthread_mutex_unlock(&work_mutex);pthread_exit(0);
}

条件变量

参考:
IBM Knowledge Center: 使用条件变量
知乎:条件变量之稀里糊涂的锁
有了互斥锁,为什么还要条件变量?
linux多线程使用pthread_cond条件变量

条件变量(cond)是在多线程程序中用来实现"等待->唤醒"逻辑常用的方法。条件变量利用线程间共享的全局变量进行同步的一种机制。

条件变量必须始终与互斥对象一起使用。主要为了防止竞争死锁(防止pthread_cond_signal在pthread_cond_wait之前调用,导致线程永久等待)。

保护条件的互斥对象必须在等待条件前被锁定。线程可等待通过调用 pthread_cond_wait 或者 pthread_cond_timedwait 子例程发信号的条件。子例程以不可分割的方式解锁互斥对象并阻塞调用线程,直到条件收到信号。当调用返回时,互斥对象再次被锁定。

pthread_cond_wait 子例程无限期阻塞线程。如果条件永不收到信号,那么线程将永不唤醒。因为 pthread_cond_wait 子例程提供取消点,所以如果启用可取消,那么退出此死锁的唯一方法是取消被阻塞的线程。

pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值。

pthread_cond_signal 子例程至少唤醒一个当前在指定条件上被阻塞的线程。根据调度策略选择被唤醒的线程。

pthread_cond_broadcast 子例程唤醒当前被阻塞在指定的条件下的每一个线程。但是,线程能够在调用子例程返回后即开始等待相同的条件。

#include <pthread.h>//定义条件变量
pthread_cond_t cond;//初始化条件变量
int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr)
//cond:事先定义好的条件变量指针
//attr:事先定义好的条件变量属性(默认NULL)//等待
1)调用时:解除锁,等待条件变量,然后阻塞
2)返回时:收到信号,再次锁定
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
//cond:初始化后的条件变量
//mutex:绑定的互斥量//定时等待
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *timeout);//发送信号
int pthread_cond_signal (pthread_cond_t *condition);//销毁条件变量
int pthread_cond_destroy (pthread_cond_t *cond)

示例:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<stdbool.h>void *thread_function1(void *arg);
void *thread_function2(void *arg);
pthread_mutex_t count_mutex;
pthread_cond_t  count_threshold_cv;
bool ready = false;
char msg1[] = "this is thread 1";
char msg2[] = "this is thread 2";
int main()
{pthread_t thread1;pthread_t thread2;pthread_mutex_init(&count_mutex, NULL);pthread_cond_init (&count_threshold_cv, NULL);pthread_create(&thread1, NULL, thread_function1, (void *)msg1);pthread_create(&thread2, NULL, thread_function2, (void *)msg2);printf("waiting for thread to finish...\n");pthread_join(thread1, NULL);pthread_join(thread2, NULL);pthread_mutex_destroy(&count_mutex);pthread_cond_destroy(&count_threshold_cv);return 0;
}void *thread_function1(void *arg)
{printf("Tips:%s\n", (char *)arg);pthread_mutex_lock(&count_mutex);while (false == ready){pthread_cond_wait(&count_threshold_cv, &count_mutex);printf("thread1 in pthread_cond_wait\n");}if(true == ready)printf("now ready = true in thread1.\n");pthread_mutex_unlock(&count_mutex);pthread_exit(0);
}void *thread_function2(void *arg)
{sleep(3);printf("Tips:%s\n", (char *)arg);pthread_mutex_lock(&count_mutex);ready = true;printf("thread2 set ready = true\n");pthread_mutex_unlock(&count_mutex);pthread_cond_signal(&count_threshold_cv);pthread_exit(0);
}

判断条件状态的时候ready==false放在了while循环中,而不是if中,这是因为pthread_cond_wait()阻塞在条件变量上的时候,即使其他的线程没有就该条件变量发出通知(pthread_cond_signal()/pthread_cond_broadcast()),条件变量也有可能会自己醒来(pthread_cond_wait()函数返回),因此需要重新检查一下共享变量上的条件成不成立,确保条件变量是真的收到了通知,否则继续阻塞等待。关于虚假唤醒的相关介绍,可以戳这里查看维基百科下面的几个引用:https://en.wikipedia.org/wiki/Spurious_wakeup。

转载于:https://www.cnblogs.com/wuxubj/p/10805386.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RUNOOB python练习题44

用来练手的python练习题&#xff0c;原题链接:python练习实例44 题干: 两个 3 行 3 列的矩阵&#xff0c;实现其对应位置的数据相加&#xff0c;并返回一个新矩阵 使用基本的List类写起来就比较麻烦&#xff0c;需要初始化一个3*3的全0矩阵&#xff0c;之后通过遍历将矩阵对应…

ImportError: No module named 'matplotlib'(python 安装各种 )

matplotlib 怎么弄啊 我应该是安装matplotlid了的 怎么还说我没有 编辑于&#xff1a;2017.03.22 12:28 0 分享 |评论0|收藏0|浏览7261 qq_37926784 声望&#xff1a; -4 3个回答 按赞数排序 用pip 也显示已经安装了matplotlib 编辑于&#xff1a;2018.03.26 19:43 分…

QBXT Day 5图论相关

图论是NOIP的一个非常重要的考点&#xff0c;换句话说&#xff0c;没有图论&#xff0c;NOIP的考纲就得少一大半&#xff08;虽然很NOIP没有考纲&#xff09; 图论这玩意吧&#xff0c;和数论一样是非常变态的东西&#xff0c;知识点又多又杂&#xff0c;但是好在一个事&#x…

RUNOOB python练习题47 交换两个变量值

用来练手的python练习题&#xff0c;原题链接: python练习实例47 题干: 两个变量值互换 在C语言C中我们要构造一个能交换两个变量值的函数很方便&#xff0c;我们可以使用指针&#xff0c;或者C中的引用。那么在没有指针的python中如何构造一个可以交换两个变量值的函数呢&am…

tensorflow一元二次函数拟合

先看下要做的内容&#xff0c;创建一元二次函数yx平方-0.5&#xff0c;其中为了更符合散点图模拟需要&#xff0c;在方程加噪点&#xff0c;以标准方差0.05行驶&#xff0c;如图所示 折线图 散点图 下面我们要做的&#xff0c;是要计算机自动拟合出该散点图的函数&#xff0…

hibernate缓存机制与N+1问题

在项目中遇到的趣事 本文基于hibernate缓存机制与N1问题展开思考&#xff0c; 先介绍何为N1问题 再hibernate中用list()获得对象&#xff1a; 1 /**2 * 此时会发出一条sql&#xff0c;将30个学生全部查询出来3 */4 List<Student> …

lambda函数 RUNOOB python练习题49

用来练手的python练习题&#xff0c;原题链接python练习实例49 该练习题主要是关于lambda函数的使用方法&#xff0c;本文就python中的lambda函数做出一点总结。 1. lambda函数的定义与调用 在python中&#xff0c;我们都知道使用def关键词来定义一个函数, 例如一个最简单的…

kubernetes(k8s)安装部署

Kubernetes是一个开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xff0c;Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署&#xff0c;规划&#xff0c;更新&#xff0c;维护的一种机制。 Kubernetes一个核心的特点就是能够自主…

react typescript 子组件调用父组件

//父组件 import * as React from reactimport { Input } from antdconst Search Input.Searchimport "./index.less"import Child from "./compon/list" interface IProps { MakeMoney?: () > void //暴露方法} export default class ProjectLis…

python random随机数 RUNOOB python练习题50

用来练手的python练习题&#xff0c;原题链接: python练习实例50、 该练习题主要包含了random模块随机数的应用&#xff0c;下面给出几个常用的模块内函数。 1. 生成浮点型随机小数 最简单的&#xff0c;就是用random函数&#xff0c;生成 [0.0,1.0)[0.0, 1.0)[0.0,1.0)范围…

Spring Cloud Eureka Consul使用和对比

Spring Cloud简介 最大的区别是Eureka保证AP, Consul为CP。 Consul强一致性(C)带来的是&#xff1a; 服务注册相比Eureka会稍慢一些。因为Consul的raft协议要求必须过半数的节点都写入成功才认为注册成功 Leader挂掉时&#xff0c;重新选举期间整个consul不可用。保证了强一致…

符号 RUNOOB python练习题 51

用来练手的python练习题&#xff0c;原题链接: python练习实例51 python中的 & 和 | 使用过程中&#xff0c;变量类型不同&#xff0c;这两个符号的作用也不同。 1. 对于数字变量&#xff0c;&\&& 和 ∣|∣ 用于逐位运算 # 二进制逐位逻辑与门运算 a 0b110…

Eclipse里的快捷键

MyEclipse 快捷键1(CTRL) ------------------------------------- Ctrl1 快速修复 CtrlD: 删除当前行 CtrlQ 定位到最后编辑的地方 CtrlL 定位在某行 CtrlO 快速显示 OutLine CtrlT 快速显示当前类的继承结构 CtrlW 关闭当前Editer CtrlK 快速定位到下一个 CtrlE 快…

Python打印杨辉三角形 RUNOOB python练习题61

用来练手的python练习题&#xff0c;原题链接: python练习实例61 题干: 打印出杨辉三角形 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1 实现代码如下: import numpy as nptable…

使用Docker快速搭建Tensorflow开发环境

当我刚开始学习使用scikit-learn时&#xff0c;总是会出现各种各样的包依赖问题&#xff0c;兜兜转转了一遍才全部安装好&#xff0c;现在的机器学习算法开发者大都使用tensorflow、pytorch来实现自己的想法&#xff0c;但依然会面临各种包版本和依赖的问题&#xff0c;有一段时…

Java服务GC参数调优案例

这段时间在整理jvm系列的文章&#xff0c;无意中发现本文&#xff0c;作者思路清晰通过步步分析最终解决问题。我个人特别喜欢这种实战类的内容&#xff0c;经原作者的授权同意&#xff0c;将文章分享于此。原文链接&#xff1a;Java服务GC参数调优案例&#xff0c;下面为转载此…

RUNOOB python 67 数组的元素互换

用来练手的Python练习题&#xff0c;原题链接:python练习实例67 题干: 输入数组&#xff0c;最大的与第一个元素交换&#xff0c;最小的与最后一个元素交换&#xff0c;输出数组 代码如下: import numpy as nptable np.array([10,4,9,3,11,25,37,15,2,231,672,22]) #定义sw…

11.13 ethtool:查询网卡参数

ethtool命令用于查询或设置网卡参数。ethtool [devname][rootlinuxprobe ~]# ethtool eth0Settings for eth0:Supported ports: [ TP ]Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: NoSupports au…

微信小程序、微信公众号、H5之间相互跳转

一、小程序和公众号 答案是&#xff1a;可以相互关联。 在微信公众号里可以添加小程序。 图片有点小&#xff0c;我把文字打出来吧&#xff1a; 可关联已有的小程序或快速创建小程序。已关联的小程序可被使用在自定义菜单和模版消息等场景中。 公众号可关联同主体的10个小程…