linux系统编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux系统编程相关的知识,希望对你有一定的参考价值。

一  IPC 对象 ---- 消息队列

IPC 对象命令

(1)查看系统中IPC对象
   ipcs  -a  显示所有的IPC对象
   ipcs  -s/-q/-m

(2)删除系统中的IPC对象
   ipcrm -q/-s/-m  ID

 
1.获得key值

第一种:
key_t ftok(const char *pathname, int proj_id);
参数:
@pathname  已经存在的文件路径
@proj_id   获取这个整数的低8bit
返回值:
成功返回 key值,失败返回-1


第二种:
将key值指定为IPC_PRIVATE ,当IPC对象在亲缘关系进程通信的时候


2.创建IPC对象
int msgget(key_t key, int msgflg);
参数:
@key        IPC_PRIVATE 或 ftok
@msgflg     IPC_CREAT | 0666  或 IPC_CREAT | IPC_EXCL | 0666 (判断IPC对象是否存在)
返回值:
成功返回ID,失败返回-1

注意:
如果对应key值的IPC对象不存在,则创建,如果存在,直接返回IPC对象的ID

3.发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
@msqid      消息队列ID
@msgp       需要发送的消息存放的地址
@msgsz      消息正文的大小
@msgflg     0:阻塞的方式发送  IPC_NOWAIT:非阻塞方式调用
返回值:
成功返回0,失败返回-1

消息结构体定义:

typedef struct{
    long  msg_type;   //消息类型必须在第一个位置,
    char  mtxt[1024];
    ...
}msg_t;

正文大小:sizeof(msg_t) - sizeof(long)

4.接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
@msqid   消息队列ID
@msgp    存放接收到的消息
@msgsz   正文大小
@msgtyp  消息类型  ,  0: 总是从消息队列中提取第一个消息
@msgflg     0:阻塞的方式接收   IPC_NOWAIT:非阻塞方式调用
返回值:
成功返回 接收消息正文大小,失败返回-1

4.删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
@msgqid  消息队列
@cmd     IPC_RMID(删除消息队列)  IPC_SET(设置消息队列的属性信息) IPC_STAT(获取消息队列属性信息)
@buf     存放消息队列属性
返回值:
成功返回0,失败返回-1

练习:
实现两个进程通信

二 共享内存 :内核空间预留出来的一块内存,用于进程间通信

(1)int shmget(key_t key, size_t size, int shmflg);

功能:获取共享内存段的ID

参数:
@key    IPC_PRIVATE  或 ftok()
@size   申请的共享内存段大小 [4k的倍数]
@shmflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL

返回值:
成功返回ID,失败返回-1

(2)void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存到用户空间
参数:
@shmid    共享内存段ID
@shmaddr  NULL:系统自动完成映射
@shmflg   SHM_RDONLY:只读   0:读写
返回值:
成功返回映射后的地址,失败返回(void *)-1

练习:A,B通过共享内存通信

B如何知道A已经写了数据?

flag_r  flag_w 
-------------------------------------------------------------------------------------
       |       |  数据 (从键盘上输入)
-------------------------------------------------------------------------------------

(3)int shmdt(const void *shmaddr);
功能:撤销映射
参数:
@shmaddr  共享内存映射的地址

注意:当一个进程结束的时候,它映射共享内存,会自动撤销映射


(4)int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:根据命令控制共享内存
参数:
@shmid  共享内存段的ID
@cmd    IPC_STAT[获取属性],IPC_SET[设置属性],IPC_RMID[删除IPC对象]
@buf    保存属性
返回值:
成功返回0,失败返回 -1

----------------------------------------------------------------------------
注意:当我们调用shmctl删除共享内存的时候,并不会立即删除。只有当共享内存映射
     次数为0,才会删除共享内存对象
-----------------------------------------------------------------------------

三 信号灯(信号量)集

POSIX 线程中的同步用的是无名信号量
进程间的同步使用的是IPC 对象[信号灯集]

信号灯集:信号灯集合,每一个信号灯都可以用来表示一类资源,其值表示资源的个数

(1)创建信号灯集
int semget(key_t key, int nsems, int semflg);
参数:
@key    IPC_PRIVATE , ftok()
@nsems  信号灯集中信号灯的个数
@semflg IPC_CREAT | 0666,IPC_CREAT | IPC_EXCL
返回值:
成功返回ID,失败返回-1

(2)初始化信号灯集中信号灯的值

int semctl(int semid, int semnum, int cmd, ...);
参数:
@semid   信号灯集的ID
@semnum  信号灯的编号[编号从0开始]
@cmd     SETVAL[设置信号灯的值]  ,GETVAL(获取信号灯的值),IPC_RMID[删除信号灯集]
返回值:
成功返回0,失败返回-1

思考:将信号灯集中的1号信号灯初始化为1?

union semun {
    int     val;    /* Value for SETVAL */
    struct semid_ds *buf;   /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array; /* Array for GETALL, SETALL */
    struct seminfo  *__buf; /* Buffer for IPC_INFO
                               (Linux-specific) */
};

void init_sem_value(int sem_id,int sem_num,int value)
{
    union semun sem_val;
   
    sem_val.val = value;
   
    if(semctl(sem_id,sem_num,SETVAL,sem_val) < 0)
    {
        ...
    }

    return ;
}

(3)PV操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:完成PV操作 
参数:
@semid  信号灯集的ID
@sops   操作方式结构体首地址
@nsops  操作信号灯的个数
返回值:
成功返回0,失败返回-1

struct sembuf
{
    unsigned short sem_num;  /* semaphore number */
    short     sem_op;   /* semaphore operation  */
    short     sem_flg;  /* operation flags */
};

sem_op :
<1>0   等待信号灯的值变成0
<2>1   释放资源,V操作
<3>-1  申请资源,P操作

sem_flg:
0           : 阻塞方式
IPC_NOWAIT  : 非阻塞方式调用
SEM_UNDO    : 进程结束的时候,它申请的资源自动释放

-----------------------------------------------------------------
void P(int sem_id,int sem_num)
{
    struct sembuf sem;

    sem.sem_num = sem_num;
    sem.sem_op  = -1;
    sem.sem_flg = 0;
   
    if(semop(sem_id,&sem,1) < 0)
    {
        ....
    }
}

void V(int sem_id,int sem_num)
{
    struct sembuf sem;

    sem.sem_num = sem_num;
    sem.sem_op  = 1;
    sem.sem_flg = 0;
   
    if(semop(sem_id,&sem,1) < 0)
    {
        ....
    }
}

练习:A,B通过信号灯集同步对共享内存操作

让创建信号灯集的进程,初始化信号灯的值 ,如果信号灯集已经存在则不初始化

sem_id = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
if(sem_id < 0)//信号灯集已经,不初始化信号灯值
{
    sem_id = semget(key,2,IPC_CREAT | 0666);

}else{
    //初始化信号灯集中信号灯的值
}
 


以上是关于linux系统编程的主要内容,如果未能解决你的问题,请参考以下文章

linux系统 C语言编程

Linux系统下C语言的编程技巧

嵌入式Linux从入门到精通之第九节:系统编程

嵌入式Linux从入门到精通之第九节:系统编程

Linux系统编程

(46)LINUX应用编程和网络编程之一Linux应用编程框架