主题:
日常练习系列。包括:
- 进程和线程(linux常用命令)
- 进程状态(linux平台)
- 系统IPC
- 实现消息队列通信代码(cpp)
代码:
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <unistd.h> //fork函数
#include <sys/ipc.h>
#include <cstring>
#include <sys/msg.h> //里买你有消息的发送函数
using namespace std;
class Message //消息的类别,必须有一个type
{
public:
Message(long t, char* s)
{
type = t;
strcpy(message, s);
}
Message()
{
}
long type;
char message[100];
};
int main()
{
//----------------进程和线程------------------------------
// 进程之间的派生过程是一个 fork and exec的过程。也就是先调用一个fork,创造一个和他自己
//一样的进程,新的进策有一个pid和ppid,ppid就是上一个进程的pid。然后以exec的方式来加载
//实际要执行的程序。
// 进程中会有一些父进程派生的子进程,如果只是杀掉子进程,那么父进程还会创造子进程。
//pid也会是一样的。有一些进程是常驻内存的。常驻内存的进程可以认为是 服务。
// 在linux下使用ps可以静态查看进程,top动态查看进程,pstree可以查看进成树。
//ps aux可以查看所有进程状态。ps -l 可以查看当前bash下的所有子进程。
//ps -lA可以查看所欲进程状态,格式和aux不一样。
// 在一个bash进程中可以同时完成多个工作,这是设计到工作管理(job control)。最简单
//的做法是在一个命令后面加上&,可以将这个进程 扔到背景中 。放到背景的进程不会被
//ctrl c终止。也就是在后台执行。但是仅仅这样的话,进程导致的标准输入输出,
//仍然会出现在屏幕上。所以可以用 数据流重导向 而就是>这个运算符。可以将一个文件
//的标准输出导向到另外一个文件中。在这里有0:标准输入 1:标准输出 2:标准错误输出
//使用&来修饰的话,就可以认为是一个文件描述符。>的前面必须是一个流,一个命令代表的其实
//是标准输出。>的后面必须是一个文件描述符,也就是代表一个文件。因此要想将2重定向到1的话
//必须用2>&1; ctrl z可以把一个进程放到后台,并且stop的状态。
//当有job在后台运行的时候,可以使用jobs命令来查看后台程序和状态
//用fg可以调到前台执行。bg可以让一个job在后台运行。
// 当想要kill掉一个进程的时候,可以用kill命令。参数-9表示强制终止,只是用于异常的进程
//-l5用于正常终止。后面默认的数字是pid,也可以加用 %job号
//-------------------进程状态----------------------
// linux中进程的状态有R(运行), S和D都表示被阻塞(S为可以被信号激活,signal,可以kill掉)
//而D表示不会被信号激活,也不会被kill掉(不常见)。T表示stop。Z表示僵尸状态。
//对应于状态图的话,就绪状态非常不常见。阻塞有两种对应状态。
// 僵尸进程的产生:当子进程退出,但是由于子进程的完全推出需要父进程的配合(调用wait)
//但是如果此时,恰好父进程不处于运行状态,比如调用sleep函数(处于S)。那么就会产生僵尸进程。
/*
pid_t pid = fork();
if(pid==0) //子进程
{
exit(0);
}
else if(pid>0){ //父进程
sleep(60); //休眠1分钟,处于S状态
}
*/
//----------------系统IPC------------------
//包括消息队列,信号量(semaphore),信号(signal),共享内存(以来信号量机制来完成同步)
//套接子通信(socket)
// 消息队列:消息队列是信息的链表,存放与内核当中。消息面向记录,消息具有特定的格式以及特定
//的优先级。消息和有名管道类似,不依赖于具体进程。不随着特定进程的退出来销毁。
//消息队列有一个id来进行标识,消息可以随机查询,按照类别进行查询。
// 信号量(semaphore)不是存储进程之间的通信数据,而是实现资源的互斥和同步。常常和共享
//内存结合来传递通信信息。依赖操作系统提供的PV原子操作。
// 信号(signal)和信号量是不一样的,而且比较复杂。
// 共享内存:是最快的IPC方式,但是需要配合信号量才可以实现多个进程的同时操作。
// socket可以实现不同主机之间的通信。socket本质上就是进程之间的通信。在网络中很常见。
//------------消息队列代码实现---------------------
//消息代码可以实现传递多种数据类型的数据流,可以实现异步传输。
key_t key = ftok("/home/xuyangli/", 'x'); //以来于ipc.h和sys/types.h 创建一个key,用来获得消息id
//参数为一个路径,一个标志,必须用单引号
if(key<0)
{
perror("create key");
return 0;
}
int msgid = msgget(key, IPC_CREAT|0666); //根据key来找到或者创建一个队列,然后返回一个id
//返回一个id,可以直接指定创建时的权限,flag非常类似open
if(msgid<0)
{
perror("getid");
return 0;
}
char m[100] = "hello hello";
Message mess(0, m);
int rs = msgsnd(msgid, &mess, sizeof(mess)-sizeof(long), IPC_NOWAIT);//非阻塞的方式
//发送函数,消息id,消息类的指针,发送的长度,发送flag(这里表示不阻塞发送)
if(rs<0)
{
perror("发送:");
return 0;
}
Message messrcv(0,NULL);
int rv = msgrcv(key, &messrcv, sizeof(messrcv), 0, IPC_NOWAIT );
if(rv<0)
{
perror("receive");
return 0;
}
return 0;
}