信号量的概念参见这里。 与消息队列和共享内存一样,信号量集也有自己的数据结构: struct semid_ds { struct ipc_perm sem_perm; /* Ownership a
几种进程间的通信方式:管道,FIFO,消息队列,他们的共同特点就是通过内核来进行通信(假设POSIX消息队列也是在内核中实现的,因为POSIX标准并没有限定它的实现方式)。向管道,FIFO,消息队列写入数据需要把数据从进程复制到内核,从这些IPC读取数据的时候又需要把数据从内核复制到进程。所以这种IPC方式往往需要2次在进程和内核之间进行数据的复制,即进程间的通信必须借助内核来传递。如下图所示:
但是在libc库中,函数sem_open、sem_close、sem_unlink只有声明,并未实现。
项目中遇到一个bug,因为接入了几家越狱平台:91、同步推、PP助手,在设备上安装了三个应用,启用其中任意一个,另外二个启动后无法创建发送socket消息,从而导致游戏直接死在登录那里,再次点击登录时线程才会被唤醒(无法发送的原因定位到,是因为在调用sem_post方法后无法将线程唤醒)。之后我尝试将信号量改为条件变量,就再也没有遇到那个问题了。具体改写的几个方法:
本文介绍了Linux信号量、POSIX信号量、Linux条件变量和Linux线程同步基本概念,并通过代码示例展示了如何使用这些技术进行线程同步。
生产者消费者问题:该问题描述了两个共享固定大小缓冲区的进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费
突然间发现zabbix 挂了,咋发现的呢?报警的世界突然安静了,你就会觉得不妥了。这是运维人员的通病,有报警嫌烦,没报警心里会不安。 1,图形界面上确实显示zabbix server is not running 2,排查zabbix server 日志 tail /var/log/zabbix/zabbix_server.log 发现有如下报警:
文章主要介绍了在Linux系统中,如何利用自旋锁来实现线程之间的同步和互斥。主要包括了自旋锁的定义、工作原理、使用方式和注意事项,并通过实例介绍了如何在C语言中实现自旋锁。
管道一般为有亲缘关系进程提供单路数据流, 通过pipe(int fd[2])创建, 返回两个文件描述符, fd[0] 用于读,fd[1]用于写。 通过 read 和 write 函数进行 操作。
信号灯概述 什么是信号灯 信号灯用来实现同步,用于多线程,多进程之间同步共享资源(临界资源)。 PV原语:信号灯使用PV原语 P原语操作的动作是: u sem减1。 u sem减1后仍大于或等于零,则进程继续执行。 u 若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。 V原语操作的动作是: u sem加1。 u 若相加结果大于零,则进程继续执行。 u 若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。 信号灯分类 按信号灯实
开发成长之路(1)-- C语言从入门到开发(入门篇一) 开发成长之路(2)-- C语言从入门到开发(函数与定制输入输出控制函数) 开发成长之路(3)-- C语言从入门到开发(讲明白指针和引用,链表很难吗?) 开发成长之路(4)-- C语言从入门到开发(距离开发,还差这一篇) 开发成长之路(5)-- C语言从入门到开发(仿ATM机项目,我写的第一个项目) 开发成长之路(6)-- C++从入门到开发(C++入门不难) 开发成长之路(6)-- C++从入门到开发(C++知名库:STL入门·容器(一)) 开发成长之路(7)-- C++从入门到开发(C++知名库:STL入门·容器(二)) 开发成长之路(8)-- C++从入门到开发(C++知名库:STL入门·容器(三)) 开发成长之路(9)-- C++从入门到开发(C++知名库:STL入门·空间配置器) 开发成长之路(10)-- C++从入门到开发(C++知名库:STL入门·算法) 开发成长之路(11)-- STL常用函数大集合 开发成长之路(12)-- Linux网络服务端编程(通识篇之熟悉操作环境) 开发成长之路(13)-- Linux网络服务端编程(通识篇)
事情是这样的,新装了一套 Linux 环境下的 19.9 RAC 环境,应用方要求关闭归档。本身此机器上有三个实例,均是近期新建的实例并安装 RU 19.9,先将节点二的实例关闭然后在节点一上关闭归档,前两个实例都完成了且正常启动,当第三个实例关闭归档时,在节点一上是正常启动了,但是在节点二启动数据库则报错了,如下图:
#include <semaphore.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
该函数的每次都用都返回两次,在父进程中返回的是子进程的PID,在子进程中返回的是0.该返回值是兴许代码推断当前进程是父进程还是子进程的根据。
首先 fork 一份 [Elasticsearch 项目] (https://github.com/elastic/elasticsearch) 的代码到自己的 github 仓库,这样看代码的时候写注释可以提交到自己的仓库。
一 线程间同步 同步:相互之间配合完成一件事情 互斥:保证访问共享资源的完整性(有你没我) POSIX 线程中同步:使用信号量实现 信号量 : 表示一类资源,它的值表示资源的个数 对资源访问: p操作(申请资源) [将资源的值 - 1] .... V操作(释放资源) [将资源的值 + 1] 1.定义信号量 sem_t sem ; 2.初始化信号量 int sem_init(sem_t *sem, int pshared, unsigned int value); 参数: @sem 信号量 @pshared 0:线程间使用 @value 初始化的信号量的值 返回值: 成功返回0,失败返回-1 3.P操作 int sem_wait(sem_t *sem); 4.V操作 int sem_post(sem_t *sem); 二 进程间通信(进程间数据交互) (1)传统进程间通信方式 [1]无名管道 [2]有名管道 [3]信号 (2)System 5 IPC对象进程间通信方式 [1]消息队列 [2]共享内存 [3]信号灯集 (3)socket通信 (4)Android系统中增加Binder进程间通信方式 Linux 支持以上所有进程间通信方式 三 管道进程间通信 (1)无名管道 特点: 只能用于具有亲缘关系进程间通信(具有亲缘关系的进程具有数据拷贝动作(复制父进程创建子进程)) int pipe(int pipefd[2]); 功能:创建一个无名管道 参数: @pipefd 获取操作无名管道的文件描述符 pipefd[0]:读无名管道 pipefd[1]:写无名管道 返回值: 成功返回0,失败返回-1 (2)管道读写规则 读端存在 ,写管道 ---->只要管道没有满,都可以写入数据到管道 读端不存在,写管道 ---->此时写管道没有意义,操作系统会发送SIGPIPE杀死写管道的进程 写端存在, 读管道 ---->此时管道中读取数据,管道中没有数据,读阻塞 写端不存在,读管道 ---->此时管道中读取数据,管道中没有数据,此时不阻塞,立即返回,返回值0 (3)有名管道 特点:可以用于任意进程间通信,它是一种特殊的文件,在文件系统存在名字, 而文件中存放的数据是在内核空间,而不是在磁盘上 1.创建一个有名管道文件 int mkfifo(const char *pathname, mode_t mode); @pathname 有名管道存在的路径 @mode 有名管道的权限 返回值: 成功返回0,失败返回-1 2.打开有名管道文件 open 如果有名管道的一端以只读的方式打开,会阻塞,直到另一端以写(只写或读写)的方式打开 如果有名管道的一端以只写的方式打开,会阻塞,直到另一端以读(只读或读写)的方式打开 3.读写操作 read /write 4.关闭管道文件 close(fd); 四 信号 信号是异步进程间通信方式 进程对信号的响应方式: <1>忽略 SIGKILL 和 SIGSTOP 不能忽略 <2>捕捉 当进程收到信号,此时执行的信号处理函数 <3>默认 大部分信号对进程的默认操作方式都是杀死进程 子进程状态发生改变的时候,操作系统向父进程发送SIGCHLD,默认对它处理方式是忽略 typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 功能:设置进程对信号处理方式 参数: @signum 信号的编号 @handler SIG_IGN : 忽略信号 SIG_DFL : 使用默认处理方式 函数名 : 捕捉方式处理 返回值: 成功返回handler,失败返回SIG_ERR 练习: 如何进行不阻塞,不轮训方式回收僵尸态子进程 2.在进程中设置一个定时器 unsigned int alarm(unsigned int seconds); 参数: @seconds 定时的时间,以秒为单位 注意: 一旦定时时间完成,操作系统就会向进程发送SIGALRM信号 A进程: 读文件,写管道 A进程结束条件:文件没有数据可读 B进程: 读管道,写文件 B进程结束条件:在
我们之前介绍过简单的read,write操作,那么会有一个问题:当驱动无法立即响应请求该怎么办?比如一个进程调用read读取数据,当没有数据可读时该怎么办,是立即返回还是等到有数据的时候;另一种情况是进程调用write向设备写数据,如果缓冲区满了或者设备正忙的时候怎么办,是立即返回还是继续等待直到设备可写?这种情况下,一般的缺省做法是使进程睡眠直到请求可以满足为止。本篇就介绍遇到这类问题驱动的处理方法。 睡眠 什么是睡眠?一个进程睡眠意味着它暂时放弃了CPU的运行权,直到某个条件发生后才可再次被系统调度。
上面的代码很简单,就是启动一个线程,然后先线程里循环打印字段字符串。我们就以这个最简单的例子来开口。
最近由于session数量增加,需要调整session,也就是要调整process参数。看是比较简单的一个问题,却遭遇了ORA-27300,ORA-27301。因为这个涉及到了有关内核参数kernel.sem的修改。下面是其具体描述。 1、故障现象 OS版本:SUSE Linux Enterprise Server 10 SP3 (x86_64) - Kernel \r (\l) DB版本: SQL*Plus: Release 10.2.0.3.0 - Production 需求:Processes参数由1000修改到2000 SQL> startup pfile=/u02/database/MRDB/initMRDB.ora; ORA-27154: post/wait create failed ORA-27300: OS system dependent operation:semget failed with status: 28 ORA-27301: OS failure message: No space left on device ORA-27302: failure occurred at: sskgpcreates 2、故障的分析与解决 #起初咋一看还以为空间不够呢,如下,显然不是空间的问题,其次有个很重要的表示"semget" SQL> ho df -h Filesystem Size Used Avail Use% Mounted on /dev/sda3 1.8T 826G 885G 49% / udev 32G 116K 32G 1% /dev /dev/sda1 99M 9.5M 85M 11% /boot #后台日志如下 Tue Aug 5 18:07:22 2014 Starting ORACLE instance (normal) Tue Aug 5 18:07:22 2014 Errors in file /u02/database/MRDB/udump/mrdb_ora_30366.trc: ORA-27154: post/wait create failed ORA-27300: OS system dependent operation:semget failed with status: 28 ORA-27301: OS failure message: No space left on device ORA-27302: failure occurred at: sskgpcreates #Google了一些文章,描述的是需要调整内核参数kernel.sem,也就是信号量的问题 v2012db02u:~ # grep kernel.sem /etc/sysctl.conf kernel.sem = 1250 32000 100 256 #这个是当前的值 信号量设置示例 SEMMSL应该设置为服务器中实例中具有最大的PROCESSES参数+10,例如,当最大的PROCESSES参数为5000时,SEMMSL应设置为5010。 SEMMNS参数应设置为SEMMSL*SEMMNI,接上例SEMMSL为5010,SEMMNI的值一般为128,则SEMMNS参数应为(5010*128)=641280。 SEMOPM参数应设置与SEMMSL参数相同,接上例此处应设置为5010 因此对于信号量建议做如下设置 sysctl -w kernel.sem="5010 641280 5010 128" #关于这个参数的具体描述及设置可以参考:Linux 内核参数优化(for oracle) #由于当前服务器存在N个实例,因此给了一个比较大的值,生产环境应慎重修改,如下 v2012db02u:~ # vi /etc/sysctl.conf v2012db02u:~ # sysctl -p ........... kernel.sem = 7000 1792000 7000 256 ........... #再次启动,狂汗.... SQL> startup pfile=/u02/database/MR/initMR.ora; ORA-00064: object is too large to allocate on this O/S (1,5150880) v2012db02u:~ > oerr ora 00064 00064, 00000, "object is too large to allocate on this O/S (%s,%s
共享内存是一个非常有意思的话题,一方面共享内存避免了通讯过程中的内存复制问题,是 Linux IPC 通讯中效率最高的一种。另一方面,因为可以直接对内存甚至其他进程的内存进行修改,利用共享内存可以实现一些常规操作无法做到的奇技淫巧。
信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在sem_wait的时候,就阻塞在那里)。当信号量为单值信号量时,也可以完成一个资源的互斥访问。信号量测重于访问者对资源的有序访问,在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
如果需要多个进程合作来完成某个任务,那个可能会存在资源争用或者其他一些意想不到的问题,这个时候,就需要通过实现进程同步来防止问题的产生。
信号量是一种计数器,用来控制对多个进程/线程共享的资源进行访问。常和锁一同使用。 在某个进程/线程正在对某个资源进行访问时,信号量可以阻止另一个进程/线程去打扰。 生产者和消费者模型是信号量的典型使用。
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。 IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享内存、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。
那天,我和共享内存、shmid不眠不休只吃一点喝一点奋战了十个小时,只为了把我的项目进度赶在大家前面,却被进程间通信始终无法打通而拦住。解决问题之后,有感而作。
PV操作是计算机领域一个有名的术语。它由荷兰人Dijkstra提出,是一种典型的同步机制,P(荷兰语passeren)表示通过,V(荷兰语vrijgeven)表示释放。
想必各位读者在看了昨天的文章分享之后,大概对线程有了一个比较清楚的认识了,但是昨天讲的东西过于纯理论化,所以在昨天的基础上,今天我们就来进行实战演练,做到活学活用,废话不多说,直接开干吧。
信号灯、互斥锁和条件变量之间的差异: 互斥锁必须由给他上锁的线程解锁,信号灯的挂出不必由执行过它的等待操作的同一线程执行 互斥锁要么被锁住要么被解开 既然信号灯有一个与之相关连的状态(它的计数值),信号灯挂出操作总是被记住。然而当想一个条件变量发送信号时,如果没有线程等待在该条件变量上,那么该信号将丢失
前因 在一次机房突然断电之后,登陆到zabbix系统中查看,发现有一台agent没有连接到,登陆到agent机器查看发现zabbix-agent服务无法启动,查看zabbix-agent日志看到如下报错信息。 .... zabbix_agentd [836]: cannot open log: cannot create semaphore set: [28] No space left on device zabbix_agentd [839]: cannot open log: cannot creat
4.一般要阻塞,就算使用 O_NONBLOCK 标志位来达到不阻塞,也要一次性把管道写满才能不阻塞,但是无法知道管道可写空间是多少
Posix IPC共有三种类型: Posix消息队列 Posix信号灯 Posix共享内存区
在 Linux 内核 中 , " 进程控制块 " 是通过 task_struct 结构体 进行描述的 ; Linux 内核中 , 所有 进程管理 相关算法逻辑 , 都是基于 task_struct 结构体的 ;
【翻译自mos文章】设置了RemoveIPC=yes 的RHEL7.2上 会crash掉Oracle asm 实例和Oracle database实例
前言:最近开始写小册子,一篇篇来,写完了再整理总结到一起。循序渐进,重点是优先分析libuv的原理。其他的有时间再写,也希望大家一起。
信号量(初值5,主进程接受一个客户连接后执行P操作判断是否超过5,转发子进程有一个客户退出后执行V操作,并发消息队列标识符)
管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
System-V的信号量是老古董,除非万不得已,否则我们一般用POSIX信号量,好用、简单、靠谱。
数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块。而操作系统则是Oracle稳定运行与最大化性能的基石。本文主要描述基于Linux系统下 Oracle 内核参数的配置。
管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,是只存在于内存中的文件,本质是内核的一块缓冲。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。管道是单向的、先进先出的、无结构的、固定大小字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。
我们使用过windows的都知道,当一个程序被卡死的时候不管怎样都没反应,这样我们就可以打开任务管理器直接强制性的结束这个进程,这个方法的实现就是和Linux上通过生成信号和捕获信号来实现相似的,运行过程中进程捕获到这些信号做出相应的操作使最终被终止。
1.假设p1先执行,执行到p(s), s-=1, 此时s=-1<0,进程阻塞,主动放弃cpu使用权,cpu调度执行p2,执行p2的具体任务,然后进行v(s),,s+=1,s=0,p2执行完毕。cpu调度继续执行p1,此时s=0,p1被唤醒,因此就达到了先执行p2后执行p1的同步关系。 2.假设p2先执行,首先执行具体的代码,然后进行v(s),s+=1,s=1>0,然后p2执行完毕。cpu调度执行p1,p1首先p(s),s-=1,s=0,然后执行具体的代码。同样也达到了先执行p2后执行p1的同步关系。 二.Linux下信号量实现同步,线程2先执行输出"hello",线程1后执行输出"world\n"的功能
__pshared 不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享
除了原子操作,中断屏蔽,自旋锁以及自旋锁的衍生锁之外,在Linux内核中还存在着一些其他同步互斥的手段。
进程与线程之间是有区别的,不过linux内核只提供了轻量进程的支持,未实现线程模型。Linux是一种“多进程单线程”的操作系统。Linux本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。
函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
1 可以得出filename正在运行的进程 #pidof filename 2 可以通过文件或者tcp udp协议看到进程 #fuser -n tcp port 3 可以看文件修改时间,大小等信息 #stat filename 4 看加载模块 #lsmod 5 看rpc服务开放 #rpcinfo -p 6 看网卡是否混杂模式(promiscuous mod) #dmesg|grep eth0 7 看命令是否被更改,象md5sum一样 #rpm -Vf /bin/ls rpm -Vf /bin/ps正常无输出
1.写出最底层Led_Open(),Led_Write(),Led_Read() 2.如何让内核知道下面有我们写好的操作硬件的函数呢?定义一个file_operations结构体(指向Led_Open等底层函数)。使用函数regsiter_chrdev(major,”first_drv”,&first_drv_fops)注册告诉内核(通过major索引)。 3.regsiter_chrdev被谁调用?被驱动入口函数调用。first_drv_init() 4.如何知道调用first_drv_init(),还是其他的函数呢?利用宏module_init(first_drv_init)定义一个结构体,结构体中有函数指针,指向入口函数。 5.出口函数first_drv_exit。卸载驱动unregsiter_chrdev(major,”first_drv”,&first_drv_fops)。如何知道何时来调用first_drv_exit?module_init(first_drv_exit)定义一个结构体,结构体中有函数指针,指向入口函数。
Ticks是从PHP 4.0.3开始才加入到PHP中的,它是一个在declare代码段中解释器每执行N条低级语句就会发生的事件。N的值是在declare中的directive部分用ticks=N来指定的。
大家好,又见面了,我是你们的朋友全栈君。 引子 在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你”不选这个内核不一定能正确的运行使用glibc的程序”,那futex是什么?和glibc又有什么关系呢? 1. 什么是Futex Futex 是Fast Userspace muTexes的缩写,由Hubertus Franke, Matthew Kirkwood, Ingo Molnar and Rusty Russell共同设计完成。几位都是linux领域的专家,其中可能Ingo Molnar大家更熟悉一些,毕竟是O(1)调度器和CFS的实现者。 Futex按英文翻译过来就是快速用户空间互斥体。其设计思想其实 不难理解,在传统的Unix系统中,System V IPC(inter process communication),如 semaphores, msgqueues, sockets还有文件锁机制(flock())等进程间同步机制都是对一个内核对象操作来完成的,这个内核对象对要同步的进程都是可见的,其提供了共享 的状态信息和原子操作。当进程间要同步的时候必须要通过系统调用(如semop())在内核中完成。可是经研究发现,很多同步是无竞争的,即某个进程进入 互斥区,到再从某个互斥区出来这段时间,常常是没有进程也要进这个互斥区或者请求同一同步变量的。但是在这种情况下,这个进程也要陷入内核去看看有没有人 和它竞争,退出的时侯还要陷入内核去看看有没有进程等待在同一同步变量上。这些不必要的系统调用(或者说内核陷入)造成了大量的性能开销。为了解决这个问 题,Futex就应运而生,Futex是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享 的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不 用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。 Linux从2.5.7开始支持Futex。 2. Futex系统调用 Futex是一种用户态和内核态混合机制,所以需要两个部分合作完成,linux上提供了sys_futex系统调用,对进程竞争情况下的同步处理提供支持。 其原型和系统调用号为 #include <linux/futex.h> #include <sys/time.h> int futex (int *uaddr, int op, int val, const struct timespec *timeout,int *uaddr2, int val3); #define __NR_futex 240 虽然参数有点长,其实常用的就是前面三个,后面的timeout大家都能理解,其他的也常被ignore。 uaddr就是用户态下共享内存的地址,里面存放的是一个对齐的整型计数器。 op存放着操作类型。定义的有5中,这里我简单的介绍一下两种,剩下的感兴趣的自己去man futex FUTEX_WAIT: 原子性的检查uaddr中计数器的值是否为val,如果是则让进程休眠,直到FUTEX_WAKE或者超时(time-out)。也就是把进程挂到uaddr相对应的等待队列上去。 FUTEX_WAKE: 最多唤醒val个等待在uaddr上进程。 可见FUTEX_WAIT和FUTEX_WAKE只是用来挂起或者唤醒进程,当然这部分工作也只能在内核态下完成。有些人尝试着直接使用futex系统调 用来实现进程同步,并寄希望获得futex的性能优势,这是有问题的。应该区分futex同步机制和futex系统调用。futex同步机制还包括用户态 下的操作,我们将在下节提到。 3. Futex同步机制 所有的futex同步操作都应该从用户空间开始,首先创建一个futex同步变量,也就是位于共享内存的一个整型计数器。 当 进程尝试持有锁或者要进入互斥区的时候,对futex执行”down”操作,即原子性的给futex同步变量减1。如果同步变量变为0,则没有竞争发生, 进程照常执行。如果同步变量是个负数,则意味着有竞争发生,需要调用futex系统调用的futex_wait操作休眠当前进程。 当进程释放锁或 者要离开互斥区的时候,对futex进行”up”操作,
领取专属 10元无门槛券
手把手带您无忧上云