linux下让进程运行在指定的cpu上

linux下让进程运行在指定的cpu上
linux下让进程运行在指定的cpu上

最近负责的svr压力比较大,业务逻辑有点复杂,能优化的地方已经全部优化了,

目前每秒3k次,cpu负载还是比较高

top看一下,4核的cpu负载不是太均衡,打算考虑一下将业务进程指定到3个cpu上运行,另外一个cpu专门负责处理网络收发包;打算尝试一下,如果还是不行,再过段时间,访问量再增加的话,就要加机器了,呜呜

补充:今天测试了一下,效果挺好,同样进程数的情况下,进行cpu绑定

每个cpu都利用起来了,负载也比不绑定的情况下好了很多

分析一下有效果的原因:

看了《linux内核设计与实现》的42节,觉得人为控制一下cpu的绑定还是有用处的

1、linux的SMP负载均衡是基于进程数的,每个cpu都有一个可执行进程队列,只有当其中一个cpu的可执行队列里进程数比其他cpu队列进程数多25%时,才会将进程移动到另外空闲cpu上,也就是说cpu0上的进程数应该是比其他cpu上多,但是会在25%以内

2、我们的业务中耗费cpu的分四种类型,(1)网卡中断(2)1个处理网络收发包进程(3)耗费cpu 的n个worker进程(4)其他不太耗费cpu的进程

基于1中的负载均衡是针对进程数,那么(1)(2)大部分时间会出现在cpu0上,(3)的n 个进程会随着调度,平均到其他多个cpu上,(4)里的进程也是随着调度分配到各个cpu上;

当发生网卡中断的时候,cpu被打断了,处理网卡中断,那么分配到cpu0上的worker进程肯定是运行不了的

其他cpu上不是太耗费cpu的进程获得cpu时,就算它的时间片很短,它也是要执行的,那么这个时候,你的worker进程还是被影响到了;按照调度逻辑,一种非常恶劣的情况是:(1)(2)(3)的进程全部分配到cpu0上,其他不太耗费cpu的进程数很多,全部分配到cpu1,cpu2,cpu3上。。那么网卡中断发生的时候,你的业务进程就得不到cpu了

如果从业务的角度来说,worker进程运行越多,肯定业务处理越快,人为的将它捆绑到其他负载低的cpu上,肯定能提高worker进程使用cpu的时间

找了个例子:

现在多CPU的趋势越来越大了. 有时候为了更好地操作机器, 需要将某个进程绑定到具体的CPU上去. 下面给出了一个进程绑定到具体的CPU上去的一个例子.

view plaincopy to clipboardprint? .........10........20........30........40........50........60........70........80........90........100.......110. (12)

0.......130.......140. (150)

#include

#include

#include

#include

#include

#define __USE_GNU

#include

#include

#include

int main(int argc, char* argv[])

{

int num = sysconf(_SC_NPROCESSORS_CONF);

int created_thread = 0;

int myid;

int i;

int j = 0;

cpu_set_t mask;

cpu_set_t get;

if (argc != 2)

{

printf("usage : ./cpu num\n");

exit(1);

}

myid = atoi(argv[1]);

printf("system has %i processor(s). \n", num);

CPU_ZERO(&mask);

CPU_SET(myid, &mask);

if (sched_setaffinity(0, sizeof(mask), &mask) == -1)

{

printf("warning: could not set CPU affinity, continuing...\n");

}

while (1)

{

CPU_ZERO(&get);

if (sched_getaffinity(0, sizeof(get), &get) == -1)

{

printf("warning: cound not get cpu affinity, continuing...\n");

}

for (i = 0; i < num; i++)

{

if (CPU_ISSET(i, &get))

{

printf("this process %d is running processor : %d\n",getpid(), i);

}

}

}

return 0;

}

#include

#include

#include

#include

#include

#define __USE_GNU

#include

#include

#include

int main(int argc, char* argv[])

{

int num = sysconf(_SC_NPROCESSORS_CONF);

int created_thread = 0;

int myid;

int i;

int j = 0;

cpu_set_t mask;

cpu_set_t get;

if (argc != 2)

{

printf("usage : ./cpu num\n");

exit(1);

}

myid = atoi(argv[1]);

printf("system has %i processor(s). \n", num);

CPU_ZERO(&mask);

CPU_SET(myid, &mask);

if (sched_setaffinity(0, sizeof(mask), &mask) == -1)

{

printf("warning: could not set CPU affinity, continuing...\n");

}

while (1)

{

CPU_ZERO(&get);

if (sched_getaffinity(0, sizeof(get), &get) == -1)

{

printf("warning: cound not get cpu affinity, continuing...\n");

}

for (i = 0; i < num; i++)

{

if (CPU_ISSET(i, &get))

{

printf("this process %d is running processor : %d\n",getpid(), i);

}

}

}

return 0;

}

下面是在两个终端分别执行了./cpu 0 ./cpu 2 后得到的结果. 效果比较明显.

QUOTE:

Cpu0 : 5.3%us, 5.3%sy, 0.0%ni, 87.4%id, 0.0%wa, 0.0%hi, 2.0%si, 0.0%st

Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu2 : 5.0%us, 12.2%sy, 0.0%ni, 82.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu4 : 0.0%us, 0.0%sy, 0.0%ni, 99.7%id, 0.3%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu5 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu6 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Cpu7 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

///////////////////////////////////////////////

CPU Affinity (CPU亲合力)

CPU亲合力就是指在Linux系统中能够将一个或多个进程绑定到一个或多个处理器上运行. 一个进程的CPU亲合力掩码决定了该进程将在哪个或哪几个CPU上运行.在一个多处理器系统中,设置CPU亲合力的掩码可能会获得更好的性能.

一个CPU的亲合力掩码用一个cpu_set_t结构体来表示一个CPU集合,下面的几个宏分别对这个掩码集进行操作:

CPU_ZERO() 清空一个集合

CPU_SET()与CPU_CLR()分别对将一个给定的CPU号加到一个集合或者从一个集合中去掉. CPU_ISSET()检查一个CPU号是否在这个集合中.

其实这几个的用法与select()函数那几个调用差不多.

下面两个函数就是最主要的了:

sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)

该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.如果pid的值为0,则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上.第二个参数cpusetsize 是

mask所指定的数的长度.通常设定为sizeof(cpu_set_t).如果当前pid所指定的CPU此时没有运行在mask所指定的任意一个CPU上,则该指定的进程会从其它CPU上迁移到mask的指定的

一个CPU上运行.

sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)

该函数获得pid所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中.即获得指定pid当前可以运行在哪些CPU上.同样,如果pid的值为0.也表示的是当前进程.

这几个宏与函数的具体用法前面已经有讲解.

关于cpu_set_t的定义

# define __CPU_SETSIZE 1024

# define __NCPUBITS (8 * sizeof (__cpu_mask))

typedef unsigned long int __cpu_mask;

# define __CPUELT(cpu) ((cpu) / __NCPUBITS)

# define __CPUMASK(cpu) ((__cpu_mask) 1 << ((cpu) % __NCPUBITS))

typedef struct

{

__cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];

} cpu_set_t;

# define __CPU_ZERO(cpusetp) \

do { \ unsigned int __i; \ cpu_set_t *__arr = (cpusetp); \

for (__i = 0; __i < sizeof (cpu_set_t) / sizeof (__cpu_mask); ++__i) \

__arr->__bits[__i] = 0; \

} while (0)

# define __CPU_SET(cpu, cpusetp) \

((cpusetp)->__bits[__CPUELT (cpu)] |= __CPUMASK (cpu))

# define __CPU_CLR(cpu, cpusetp) \

((cpusetp)->__bits[__CPUELT (cpu)] &= ~__CPUMASK (cpu))

# define __CPU_ISSET(cpu, cpusetp) \

(((cpusetp)->__bits[__CPUELT (cpu)] & __CPUMASK (cpu)) != 0)

在我的机器上sizeof(cpu_set_t)的大小为128,即一共有1024位.第一位代表一个CPU号.某一位为1则表示某进程可以运行在该位所代表的cpu上.例如

CPU_SET(1, &mask);

则mask所对应的第2位被设置为1.

此时如果printf("%d\n", mask.__bits[0]);就打印出2.表示第2位被置为1了.

Linux系统编程实验六进程间通信

实验六:进程间通信 实验目的: 学会进程间通信方式:无名管道,有名管道,信号,消息队列, 实验要求: (一)在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道(二)在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号(三)创建一消息队列,实现向队列中存放数据和读取数据 实验器材: 软件:安装了Linux的vmware虚拟机 硬件:PC机一台 实验步骤: (一)无名管道的使用 1、编写实验代码pipe_rw.c #include #include #include #include #include #include int main() { int pipe_fd[2];//管道返回读写文件描述符 pid_t pid; char buf_r[100]; char* p_wbuf; int r_num; memset(buf_r,0,sizeof(buf_r));//将buf_r初始化 char str1[]=”parent write1 “holle””; char str2[]=”parent write2 “pipe”\n”; r_num=30; /*创建管道*/ if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } /*创建子进程*/ if((pid=fork())==0) //子进程执行代码 {

//1、子进程先关闭了管道的写端 close(pipe_fd[1]); //2、让父进程先运行,这样父进程先写子进程才有内容读sleep(2); //3、读取管道的读端,并输出数据 if(read(pipe_fd[0],buf_r, r_num)<0) { printf(“read error!”); exit(-1); } printf(“%s\n”,buf_r); //4、关闭管道的读端,并退出 close(pipe_fd[1]); } else if(pid>0) //父进程执行代码 { //1、父进程先关闭了管道的读端 close(pipe_fd[0]); //2、向管道写入字符串数据 p_wbuf=&str1; write(pipe_fd[1],p_wbuf,sizof(p_wbuf)); p_wbuf=&str2; write(pipe_fd[1],p_wbuf,sizof(p_wbuf)); //3、关闭写端,并等待子进程结束后退出 close(pipe_fd[1]); } return 0; } /*********************** #include #include #include #include #include #include int main() { int pipe_fd[2];//管道返回读写文件描述符 pid_t pid; char buf_r[100]; char* p_wbuf; int r_num;

Linux进程间通信(2)实验报告

实验六:Linux进程间通信(2)(4课时) 实验目的: 理解进程通信原理;掌握进程中信号量、共享内存、消息队列相关的函数的使用。实验原理: Linux下进程通信相关函数除上次实验所用的几个还有: 信号量 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。要调用的第一个函数是semget,用以获得一个信号量ID。 int semget(key_t key, int nsems, int flag); key是IPC结构的关键字,flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。nsems是该集合中的信号量数。如果是创建新集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。 semctl函数用来对信号量进行操作。 int semctl(int semid, int semnum, int cmd, union semun arg); 不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。 semop函数自动执行信号量集合上的操作数组。 int semop(int semid, struct sembuf semoparray[], size_t nops); semoparray是一个指针,它指向一个信号量操作数组。nops规定该数组中操作的数量。 ftok原型如下: key_t ftok( char * fname, int id ) fname就是指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。 当成功执行的时候,一个key_t值将会被返回,否则-1 被返回。 共享内存 共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。首先要用的函数是shmget,它获得一个共享存储标识符。 #include #include #include int shmget(key_t key, int size, int flag); 当共享内存创建后,其余进程可以调用shmat()将其连接到自身的地址空间中。 void *shmat(int shmid, void *addr, int flag); shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地

Linux进程通信实验报告

Linux进程通信实验报告 一、实验目的和要求 1.进一步了解对进程控制的系统调用方法。 2.通过进程通信设计达到了解UNIX或Linux系统中进程通信的基本原理。 二、实验内容和原理 1.实验编程,编写程序实现进程的管道通信(设定程序名为pipe.c)。使 用系统调用pipe()建立一条管道线。而父进程从则从管道中读出来自 于两个子进程的信息,显示在屏幕上。要求父进程先接受子进程P1 发来的消息,然后再接受子进程P2发来的消息。 2.可选实验,编制一段程序,使其实现进程的软中断通信(设定程序名为 softint.c)。使用系统调用fork()创建两个子进程,再用系统调用 signal()让父进程捕捉键盘上来的中断信号(即按Del键),当父进程 接受这两个软中断的其中一个后,父进程用系统调用kill()向两个子 进程分别发送整数值为16和17的软中断信号,子进程获得对应软中 断信号后分别输出相应信息后终止。 三、实验环境 一台安装了Red Hat Linux 9操作系统的计算机。 四、实验操作方法和步骤 进入Linux操作系统,利用vi编辑器将程序源代码输入并保存好,然后 打开终端对程序进行编译运行。 五、实验中遇到的问题及解决 六、实验结果及分析 基本实验 可选实验

七、源代码 Pipe.c #include"stdio.h" #include"unistd.h" main(){ int i,j,fd[2]; char S[100]; pipe(fd); if(i=fork==0){ sprintf(S,"child process 1 is sending a message \n"); write(fd[1],S,50); sleep(3); return; } if(j=fork()==0){ sprintf(S,"child process 2 is sending a message \n"); write(fd[1],S,50); sleep(3); return;

linux进程间通讯的几种方式的特点和优缺点

1. # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 # 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 # 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 # 消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 # 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。#共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。 # 套接字( socket ) :套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 管道的主要局限性正体现在它的特点上: 只支持单向数据流; 只能用于具有亲缘关系的进程之间; 没有名字; 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等; 2. 用于进程间通讯(IPC)的四种不同技术: 1. 消息传递(管道,FIFO,posix和system v消息队列) 2. 同步(互斥锁,条件变量,读写锁,文件和记录锁,Posix和System V信号灯) 3. 共享内存区(匿名共享内存区,有名Posix共享内存区,有名System V共享内存区) 4. 过程调用(Solaris门,Sun RPC) 消息队列和过程调用往往单独使用,也就是说它们通常提供了自己的同步机制.相反,共享内存区

Linux下的进程间通信-详解

Linux下的进程间通信-详解 详细的讲述进程间通信在这里绝对是不可能的事情,而且笔者很难有信心说自己对这一部分内容的认识达到了什么样的地步,所以在这一节的开头首先向大家推荐著 名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文译本《UNIX环境高级编程》已有机械工业出版社出版,原文精彩,译文同样地道,如果你的确对在Linux下编程有浓 厚的兴趣,那么赶紧将这本书摆到你的书桌上或计算机旁边来。说这么多实在是难抑心中的景仰之情,言归正传,在这一节里,我们将介绍进程间通信最最初步和最 最简单的一些知识和概念。 首先,进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信息,事实上,在很多应用系统里,都使用了这种方法。但一般说来, 进程间通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系 统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信 方法:管道、消息队列、共享内存、信号量、套接口等等。下面我们将逐一介绍。 2.3.1 管道 管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。 无名管道由pipe()函数创建: #include int pipe(int filedis[2]); 参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。下面的例子示范了如何在父进程和子进程间实现通信。 #define INPUT 0 #define OUTPUT 1 void main() { int file_descriptors[2]; /*定义子进程号 */ pid_t pid; char buf[256]; int returned_count; /*创建无名管道*/ pipe(file_descriptors); /*创建子进程*/ if((pid = fork()) == -1) { printf("Error in fork\n"); exit(1); } /*执行子进程*/ if(pid == 0) { printf("in the spawned (child) process...\n"); /*子进程向父进程写数据,关闭管道的读端*/ close(file_descriptors[INPUT]); write(file_descriptors[OUTPUT], "test data", strlen("test data"));

04--Linux系统编程-进程间通信

IPC方法 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。 在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有: ①管道(使用最简单) ②信号(开销最小) ③共享映射区(无血缘关系) ④本地套接字(最稳定) 管道 管道的概念: 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质: 1. 其本质是一个伪文件(实为内核缓冲区) 2.由两个文件描述符引用,一个表示读端,一个表示写端。 3. 规定数据从管道的写端流入管道,从读端流出。 管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。 管道的局限性: ①数据自己读不能自己写。 ②数据一旦被读走,便不在管道中存在,不可反复读取。 ③由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。 ④只能在有公共祖先的进程间使用管道。

常见的通信方式有,单工通信、半双工通信、全双工通信。 pipe函数 创建管道 int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno 函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] →r;fd[1] →w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。 管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤: 1.父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。 2.父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。 3.父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。 练习:父子进程使用管道通信,父写入字符串,子进程读出并,打印到屏幕。【pipe.c】 思考:为甚么,程序中没有使用sleep函数,但依然能保证子进程运行时一定会读到数据呢? 管道的读写行为 使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志): 1.如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

Linux进程间通信程序设计

计算机与信息技术学院设计性实验报告 一、实验目的 (1)理解进程概念; (2)理解并掌握多进程开发模式; (3)理解并掌握Linux平台进程间数据的传送方法。 二、总体设计 (1)实验内容:编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,创建两个二个子进程P1和P2分别向管道各写一句话: Message from child P1! Message from child P2! 父进程从管道中读出二个来自子进程的信息并显示。 (2)设计原理: 所谓管道,是指能够连接一个写进程和一个读进程、并允许它们进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。 通过管道的信息流 三、实验步骤: #include

#include #include #include # include #define BUFSIZE 100 int pid1,pid2; int main() { int fd[2]; char buf_out [BUFSIZE], buf_in [BUFSIZE]; if (pipe(fd) < 0) { printf("pipe error\n"); exit(1); } /*创建一个管道*/ if ((pid1 = fork()) < 0) /*创建子进程1*/ { printf("fork1 failure\n"); exit(1); } else if (pid1 == 0) { lockf(fd[1],1,0); strcpy(buf_out," Message from child P1!"); /*把串放入数组buf_out中*/ write(fd[1],buf_out,BUFSIZE); /*向管道写长为BUFSIZE字节的串*/ sleep(5); /*自我阻塞5秒*/ lockf(fd[1],0,0); exit(0); } else { while((pid2=fork( ))==-1); /*创建子进程2*/ if(pid2==0) { lockf(fd[1],1,0); /*互斥*/ sprintf(buf_out,"Message from child %d!",getpid()); write(fd[1], buf_out,BUFSIZE); sleep(5); lockf(fd[1],0,0); exit(0); } else { wait(0); /*同步*/ read(fd[0], buf_in,BUFSIZE); /*从管道中读长为BUFSIZE字节的串*/ printf("%s\n", buf_in); wait(0); read(fd[0], buf_in,BUFSIZE); printf("%s\n", buf_in); exit(0); } }

linux管道通信(C语言)

Linux环境中管道通信的实现 ?摘要Linux系统提供了丰富的进程通信手段,如信号、信号灯、管道、共享内存、消息队列等,能有效地完成多个进程间的信息共享和数据交换。本文主要设 计了Linux环境中的管道通信,并给出了利用该技术制作程序运行进程通信的实 例。 ?关键词管道;进程通信;IPC;Motif;进程条 1 引言 Linux系统提供了丰富的进程通信手段,如信号、信号灯、管道、共享内存、消息队列等,能有效地完成多个进程间的信息共享和数据交换。管道作为最早的进程间通信机制之一,可以在进程之间提供简单的数据交换和通信功能。 2 管道技术简介 2.1 管道的概念及特点 管道分为无名管道和有名管道两种。无名管道可用于具有亲缘关系进程间的通信,如父子进程、兄弟进程。有名管道克服了管道没有名字的限制,允许无亲缘关系进程间的通信。本文应用的是无名管道通信机制。 管道具有以下特点: (1)管道是半双工的,数据只能单向流动;需要相互通信时,就要建立两个管道。 (2)只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程,有名管道则突破了这一限制)。 (3)单独构成一种独立的文件系统,并且只存在于内存中。 (4)数据的读出和写入都是单向的:一个进程向管道中写的数据被管道另一端的进程读出。写入的数据每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。 2.2 管道的创建 #include int pipe(int fd[2]) 该函数是Linux的一个系统调用,其创建的管道两端处于一个进程中间。要用其实现父子进程之间的通信则需要在由pipe()创建管道后,再由系统调用fork创建一个新的子进程,然后通过管道在这两个进程间传送数据,实现进程间的通信(同样,不是父子关系和两个进程,只要两个进程中存在亲缘关系

实验三2_Linux进程间通信

实验三2_Linux进程间通信 实验三 Linux进程间通信 一、实验目的 熟悉Linux下进程间通信机制,能够使用系统提供的各种通信机制实现并发进程间的数据交换。 二、实验题目 分别使用Linux下的共享存储区、消息、管道等通信机制,编程实现并发进程之间的相互通信。 三、背景材料 (一)需要用到的系统调用 实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。 fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行; wait() 等待子进程执行完成; getpid() 获取当前进程id; shmget() 建立一个共享存储区; shmctl() 操纵一个共享存储区; shmat() 把一个共享存储区附接到进程内存空间; shmdt() 把一个已经附接的共享存储区从进程内存空间断开; msgget() 建立一个消息队列; msgctl() 操纵一个消息队列; msgsnd() 发送消息; msgrcv() 接收消息;

signal() 设置对信号的处理方式或处理过程; pipe() 打开管道; lockf() 锁定一个文件。 (二)使用共享存储区的示例程序 下面程序主要用来演示共享存储区的使用方法:首先要使用shmget得到共享存储区句柄(可以新建或连接已有的共享存储区,以关键字标识),然后使用shmat挂接到进程的存储空间(这样才能够访问),当使用完后,使用shmctl释放(shmctl 还可以完成一些其他功能)。这种使用逻辑也适用于消息和信号量。示例程序代码如下: #include #include #include #include #include int main(void) { int x, shmid; int *shmptr; if((shmid=shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666)) < 0) printf("shmget error"), exit(1); //函数原型int shmget(key_t key,int size,int shmflg); 函数用于创建(或者获取)一 key键值指定的共享内存对象,返回该对象的系统标识符:shmid;size 是创个由

操作系统课程设计:Linux系统管理实践与进程通信实现

操作系统课程设计:Linux系统管理实践与进程通信实现

操作系统课程设计——Linux系统管理实践与进程通信实现 班级网络10 学号 31006100 姓名 YHD 指导老师詹永照

二零一三年一月八号 一、设计内容 1、Linux系统的熟悉与常用操作命令的掌握。 2、Linux环境下进程通信的实现。(实现父母子女放水果吃水果的同步互斥问题,爸爸放苹果,女儿专等吃苹果,妈妈放橘子,儿子专等吃橘子,盘子即为缓冲区,大小为5。) 二、Linux环境介绍 1、Linux的由来与发展 Linux是一种可以在PC机上执行的类似UNIX的操作系统,是一个完全免费的操作系统。1991年,芬兰学生Linux Torvalds开发了这个操作系统的核心部分,因为是Linux改良的minix系统,故称之为Linux。 2、Linux的优点 (1)Linux具备UNIX系统的全部优点 Linux是一套PC版的UNIX系统,相对于Windows是一个十分稳定的系统,安全性好。 (2)良好的网络环境 Linux与UNIX一样,是以网络环境为基础的操作系统,具备完整的网络功能,提供在Internet或Intranet的邮件,FTP,www等各种服务。 (3)免费的资源 Linux免费的资源和公开的源代码方便了对操作系统的深入了解,给编程爱好者提供更大的发挥空间。 3、Linux的特点 1)全面的多任务,多用户和真正的32位操作系统 2)支持多种硬件,多种硬件平台

3)对应用程序使用的内存进行保护 4)按需取盘 5)共享内存页面 6)使用分页技术的虚拟内存 7)优秀的磁盘缓冲调度功能 8)动态链接共享库 9)支持伪终端设备 10)支持多个虚拟控制台 11)支持多种CPU 12)支持数字协处理器387的软件模拟 13)支持多种文件系统 14)支持POSIX的任务控制 15)软件移植性好 16)与其它UNIX系统的兼容性 17)强大的网络功能 三、常用命令介绍 1、目录操作 和DOS相似,Linux采用树型目录管理结构,由根目录(/)开始一层层将 子目录建下去,各子目录以 / 隔开。用户login后,工作目录的位置称为 home directory,由系统管理员设定。‘~’符号代表自己的home directory,例 如 ~/myfile 是指自己home目录下myfile这个文件。 Linux的通配符有三种:’*’和’?’用法与DOS相同,‘-‘代表区间内 的任一字符,如test[0-5]即代表test0,test1,……,test5的集合。 (1)显示目录文件 ls 执行格式: ls [-atFlgR] [name] (name可为文件或目录名称) 例: ls 显示出当前目录下的文件 ls -a 显示出包含隐藏文件的所有文件 ls -t 按照文件最后修改时间显示文件 ls -F 显示出当前目录下的文件及其类型

linux进程通信

一、linux下进程间通信概述 AT&T的贝尔实验室,对UNIX早期的进程间通信进行了改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内。 BSD(加州大学伯克利分校伯克利软件发布中心),跳过了该限制,形成了基于套接字(socket)的进程间通信机制。 linux继承了上述所有通信方式: 1、传统通信方式 无名管道(pipe),有名管道(fifo),信号(signal) 2、system V IPC对象 共享内存(share memory),消息队列(message queue),信号灯(又叫信号灯集,与线程中的信号灯要区分清楚,semaphore) 3、BSD 套接字(socket,这个其实主要用于网络间线程通信,所以肯定可以支持本机线程通信) 二、每种通信方式的介绍 1、无名管道(pipe) 无名管道只能用于具有亲缘关系的进程间通信,即父子进程,兄弟进程等。 无名管道由内核来维护,是一种半双工的通信模式,具有固定的读端和写端(读端只能读,写端只能写),可以将其看成文件,使用write和read函数进行读写。 由于子进程完全继承父进程打开的文件描述符,所以父子进程可以通过pipe进行通信 创建无名管道pipe需要用到函数: int pipe(int fd[2]);

fd[0]固定为读端,fd[1]固定为写端。 举例如下: int fd[2]; pipe(fd); 这样,一个进程通过fd[1]写入数据,另一个就可以从fd[0]读出来了。 注意无名管道无读者时,写操做将会返回一个信号,如果进程未对此信号进行捕捉,会被信号杀死(即进程退出)。 若无写者,则读操作会返回0 无名管道不能保证原子性,既如果有多个进程同时向同一个管道里面写数据,可能会造成数据交错,得不到我们想要的结果,这点希望读者能够在编程时注意。 2、有名管道fifo 有名管道可以使互不相关的两个进程之间进行通信,有名管道想普通文件一样在linux文件系统中可见,可以通过路径来指定,用open,write,read等函数进行操作,而且他与无名管道不通,他可以保证写入数据的原子性,而且遵循先进先出的原则。 使用模型: 有名管道创建函数mkfifo: int mkfifo(const char *filename,mode_t mode); 由函数原型可以看出他与open()函数基本类似: 返回值:0(成功)-1(错误)

linux进程间通讯的几种方式

1.信号:(signal)是一种处理异步事件的方式。信号时比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程外,还可以发送信号给进程本身。 2.信号量:(Semaphore)进程间通信处理同步互斥的机制。是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。 linux进程间通讯的几种方式的特点和优缺点,和适用场合 1. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

linux下进程间传递描述符(recvmsg与sendmsg)详解

进程间传递描述符 每个进程都拥有自己独立的进程空间,这使得描述符在进程之间的传递变得有点复杂,这个属于高级进程间通信的内容,下面就来说说。顺便把 Linux 和 Windows 平台都讲讲。 Linux 下的描述符传递 Linux 系统系下,子进程会自动继承父进程已打开的描述符,实际应用中,可能父进程需要向子进程传递“后打开的描述符”,或者子进程需要向父进程传递;或者两个进程可能是无关的,显然这需要一套传递机制。 简单的说,首先需要在这两个进程之间建立一个 Unix 域套接字接口作为消息传递的通道( Linux 系统上使用 socketpair 函数可以很方面便的建立起传递通道),然后发送进程调用 sendmsg 向通道发送一个特殊的消息,内核将对这个消息做特殊处理,从而将打开的描述符传递到接收进程。 然后接收方调用 recvmsg 从通道接收消息,从而得到打开的描述符。然而实际操作起来并不像看起来那样单纯。 先来看几个注意点: 1 需要注意的是传递描述符并不是传递一个 int 型的描述符编号,而是在接收进程中创建一个新的描述符,并且在内核的文件表中,它与发送进程发送的描述符指向相同的项。 2 在进程之间可以传递任意类型的描述符,比如可以是 pipe , open , mkfifo 或 socket , accept 等函数返回的描述符,而不限于套接字。 3 一个描述符在传递过程中(从调用 sendmsg 发送到调用 recvmsg 接收),内核会将其标记为“在飞行中”( in flight )。在这段时间内,即使发送方试图关闭该描述符,内核仍会为接收进程保持打开状态。发送描述符会使其引用计数加 1 。 4 描述符是通过辅助数据发送的(结构体 msghdr 的 msg_control 成员),在发送和接收描述符时,总是发送至少 1 个字节的数据,即使这个数据没有任何

Linux进程间通信方式--本地socket

1.//s_unix.c 2.#include 3.#include 4.#include 5.#include 6.#define UNIX_DOMAIN "/tmp/UNIX.domain" 7.int main(void) 8.{ 9. socklen_t clt_addr_len; 10. int listen_fd; 11. int com_fd; 12. int ret; 13. int i; 14. static char recv_buf[1024]; 15. int len; 16. struct sockaddr_un clt_addr; 17. struct sockaddr_un srv_addr; 18. listen_fd=socket(PF_UNIX,SOCK_STREAM,0); 19. if(listen_fd<0) 20. { 21. perror("cannot create communication socket"); 22. return 1; 23. } 24. 25. //set server addr_param 26. srv_addr.sun_family=AF_UNIX; 27. strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_p ath)-1); 28. unlink(UNIX_DOMAIN); 29. //bind sockfd & addr 30. ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_a ddr)); 31. if(ret==-1) 32. { 33. perror("cannot bind server socket"); 34. close(listen_fd); 35. unlink(UNIX_DOMAIN); 36. return 1; 37. } 38. //listen sockfd 39. ret=listen(listen_fd,1); 40. if(ret==-1) 41. { 42. perror("cannot listen the client connect request");

linux多进程和进程间通信

物联网学院 20 15 / 2016 学年第 1 学期实验报告 课程名称:linux编程基础 实验名称:linux多进程和进程间通信 班级学号: 学生姓名: 指导教师 日期:20 15年12 月

实验六linux多进程与进程间通信 一、实验目的 熟悉linux系统编程方法 熟悉linux常用的系统调用 二、实验环境 PC机一台 安装虚拟机版的linux操作系统一台 三、实验预习 熟悉进程创建/线程创建系统调用 熟悉进程间通信系统的调用 四、实验内容 Linux fork调用 进程间通信系统调用:管道通信 五、实验步骤 编写一个程序,实现如下功能: 创建两个子进程,父进程向管道中按照顺序输入数字1 2 3 4 5 6……,另外两个子进程分别从管道中按照顺序读出奇数和偶数,及子进程1读出的数据应该是1 3 5 7 9……,而子进程读出的数据应该是2 4 6 8 10 ……数据,要求按先读奇数,再读偶数的顺序进行 程序代码如下: #include #include

#include #include int pid1,pid2; main( ) { int fd[2],i=0,j=0; char outpipe[100],inpipe1[100],inpipe2[100],outpipe1[100]; pipe(fd); /*创建一个管道*/ while ((pid1=fork( ))==-1); /*向管道中写入字符123456789*/ lockf(fd[1],1,0); sprintf(outpipe,"123456789"); write(fd[1],outpipe,50); lockf(fd[1],0,0); /*----------------------------------*/ /*子进程1先读取管道中所有的字符,再重新把不需要的字符写入管道*/ if(pid1==0) { lockf(fd[0],1,0); read(fd[0],inpipe1,10); for(i=0;i<10;i++)//把不需要的字符写入管道

Linux间进程通信

Linux进程间通信 1 进程间通信概述 由于进程都拥有各自的用户地址空间,彼此之间是互相独立的,所以进程间不能直接访问。而很多情况下正需要这种进程间的通信,来实现多进程协同工作。因此内核提供了一种机制解决了这一问题,这就是进程间通信(IPC,Inter-Process Communication)。 进程间通信主要有以下几个目的: ·数据传输:一个进程需要将它的数据发送给另一个进程。 ·资源共享:多个进程之间共享同样的资源。 ·通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件。 ·进程控制:有些进程希望完全控制另一个进程的执行。 Linux 下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。A T&T的贝尔实验室对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,通信进程局限在单个计算机内。而BSD(加州大学伯克利分校的伯克利软件发布中心)则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。由于Unix版本的多样性,电子电气工程协会(IEEE)开发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(PSOIX,Protable Operating System Interface),现有大部分Unix和流行版本都是遵循POSIX标准,而Linux从一开始就遵循POSIX标准,拥有POSIX IPC。则Linux支持的IPC如下图所示: 图1 Linux所继承的进程间通信 其中,最初Unix IPC包括:管道、FIFO、信号; System V IPC包括:System V消息队列、System V信号灯、System V共享内存区; POSIX IPC包括:POSIX消息队列、POSIX信号灯、POSIX共享内存区。 现在在Linux下使用较多的进程间通信方式主要有以下几种: (1)管道(Pipe):管道又分为无名管道(Pipe)与有名管道(FIFO),管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信; (2)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身; (3)消息队列:消息队列是消息的链接表,包括POSIX消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。 (4)共享内存:可以说这是最有用的通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种通信方式依靠某种同步机制,如互斥锁与信号量等。(5)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

实验八 Linux进程间通信——管道与信号

《嵌入式操作系统应用开发》 课程实验报告 班级:**************** 学号:************* 姓名:************** 指导老师:*************** 成绩:

实验八:Linux进程间通信-管道与信号 一、目的与任务 目的:了解掌握操作系统管道与信号的特点与功能,学会借助管道与信号的功能函数进行编程。 任务:利用C语言指令编写程序调用管道与信号函数,完成相应功能。 二、内容、要求与安排方式 1、实验内容与要求: 1)验证管道和命名管道函数功能。 2)利用信号进行进程间的通信 2、实验安排方式:采用1人1组,上机在Linux系统下进行编程实验。 三、程序清单 (1)创建管道,父进程向子进程发送数据; #include "ch11.h" int main (void) { pid_t pid; int n, mypipe[2]; char buffer[BUFSIZ+1], some_data[] = "Hello, world!"; /* 创建管道*/ if (pipe (mypipe)) err_exit("Pipe failed.\n"); /* 派生子进程*/ if ((pid = fork())==(pid_t)0) { /* 这是子进程*/ close(mypipe[1]); /* 子进程关闭管道输出端*/ n = read(mypipe[0], buffer, BUFSIZ); printf("child %d: read %d bytes: %s\n",getpid(),n,buffer); } else { /* 这是父进程*/ close(mypipe[0]); /* 父进程关闭管道输入端*/ n = write(mypipe[1], some_data, strlen(some_data));

Linux系统编程实验六:进程间通信

实验六:进程间通信 ●实验目的: 学会进程间通信方式:无名管道,有名管道,信号,消息队列, ●实验要求: (一)在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道(二)在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号 (三)创建一消息队列,实现向队列中存放数据和读取数据 ●实验器材: 软件:安装了Linux的vmware虚拟机 硬件:PC机一台 ●实验步骤: (一)无名管道的使用

write(pipe_fd[1],p_wbuf,sizeof(str1)); sleep(1); p_wbuf=str2; write(pipe_fd[1],p_wbuf,sizeof(str2)); close(pipe_fd[1]);//3、关闭写端,并等待子进程结束后退出 exit(1); //printf("father error!"); } return 0; } **************************/ 2、编译应用程序pipe_rw.c 3、运行应用程序 子进程先睡两秒让父进程先运行,父进程分两次写入“hello”和“pipe”,然后阻塞等待子进程退出,子进程醒来后读出管道里的容并打印到屏幕上再退出,父进程捕获到子进程退出后也退出 4、由于fork函数让子进程完整地拷贝了父进程的整个地址空间,所以父子进程都有管道的读端和写端。我们往往希望父子进程中的一个进程写一个进程读,那么写的进程最后关掉读端,读的进程最好关闭掉写端 (二)信号处理 #include

{ fprintf(stderr,"cannot handle SIGBUS\n"); exit(EXIT_FAILURE); } pause();//将进程挂起直到捕捉到信号为止 exit(0); return 0; } ***************************/ 用signal系统调用为SIGBUS信号注册信号处理函数my_func,然后将进程挂起等待SIGBUS信号。所以需要向该进程发送SIGBUS信号才会执行自定义的信号处理函数 2、编译应用程序sig_bus.c 3、运行应用程序 先先一个终端中运行sig_bus,会看到进程挂起,等待信号 然后在另一个终端中,查找到运行sig_bus这个产生的进程号,用kill命令发送SIGBUS信号给这个进程 我们可以看到前面挂起的进程在接收到这个信号后的处理

相关文档
最新文档