我无聊的时候写了一个自己跟自己说话的程序
我原本的想法是同时打开两个终端,运行同一个程序,然后互相说话
用IPC实现的,编译也通过了
可是P操作总是返回0,不返回-1
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int P(int semid)
{
struct sembuf sops = {0,-1,IPC_NOWAIT};
int t = semop(semid,&sops,1);
return t;
}
int V(int semid)
{
struct sembuf sops = {0,1,SEM_UNDO};
return (semop(semid,&sops,1));
}
#define length 1024
int main()
{
int shmkey= ftok("./share",1);
int semkey= ftok("./shmem",1);
int shmid,semid;
int wait = 0;
char *shmptr;
//生成共享内存和信号量
if((shmid = shmget(shmkey,length,IPC_CREAT))==-1)
{
perror("shmget error \n");
exit(1);
}
semid = semget(semkey,1,IPC_CREAT);
if(semid==-1)
{
semid = semget(semkey,1,IPC_EXCL);
if(semid ==-1)
{
perror("semget error \n");
exit(1);
}
}
//信号量置1
union semun arg;
arg.val = 1;
if((int)(shmptr=(char*)(shmat(shmid,NULL,0)))==-1)
{
perror("shmat error \n");
exit(1);
}
if(semctl(semid,0,SETVAL,arg)==-1)
{
perror("semctl error \n");
semctl(semid,0,IPC_RMID,arg);
exit(1);
}
//开始聊天
while(1)
{
while( (P(semid) == -1)||(semctl(semid,0,GETZCNT,arg)>0))//gdb检查是出问题的地方,每次都不会进入这个循环
{
printf("waiting for enter...");
wait = 1;
sleep(1);
}
if( wait==1 )
{
printf(":%s\n",shmptr);
}
printf("say something:");
scanf("%s",shmptr);
while( V(semid) == -1)
{
printf("wait transferring \n");
sleep(3);
}
}
return 0;
}
[解决办法]
(semctl(semid,0,GETZCNT,arg)>0)
看看errno是什么
------解决方案--------------------
程序改了一下,只能保证正确运行,但不怎么优美和健壮,主要应正确使用API
如果上次非法退出进程,在再次运行程序之前,需要清理一下内核对象
program destory
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
union semun {
int val;
struct semid_ds * buf;
unsigned short * array;
struct seminfo * __buf;
};
int P(int semid) {
struct sembuf sops = { 0, -1, IPC_NOWAIT };
int t = semop(semid, &sops, 1);
return t;
}
int V(int semid) {
struct sembuf sops = { 0, 1, SEM_UNDO };
return (semop(semid, &sops, 1));
}
#define length 1024
int main(int argc, char *argv[]) {
// 生成key,必须在当前目录下存在share和shmem文件,否则错误,返回-1
int shmkey = ftok("share", 1);
int semkey = ftok("shmem", 1);
printf("%d\n", shmkey);
printf("%d\n", semkey);
// 根据key新创建共享内存
int shmid = shmget(shmkey, length, IPC_CREAT
[解决办法]
IPC_EXCL);
if (shmid == -1) {
// 如果新创建失败,则以访问的形式操作共享内存
shmid = shmget(shmkey, 0, 0);
if (shmid == -1) {
perror("shmget error \n");
exit(1);
}
}
// 根据key新创建信号量
int semid = semget(semkey, 1, IPC_CREAT
[解决办法]
IPC_EXCL);
union semun arg;
arg.val = 1;
if (semid == -1) {
printf("client get sem\n");
semid = semget(semkey, 0, 0);
if (semid == -1) {
perror("semget error \n");
exit(1);
}
} else {
// 新的信号量创建成功,设置资源数为1
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl error \n");
semctl(semid, 0, IPC_RMID, arg);
exit(1);
}
}
int ret;
// 此处用于因上一次非法退出进程而未销毁内核对象
// system v的内核对象是持久化的,即使所有访问进程终止了,
// 该内核对象还存在,不会自动销毁
if (argc > 1 && !strcmp(argv[1], "destory")) {
ret = semctl(semid, 0, IPC_RMID);
if (ret != 0) {
perror("semctl destory sem error");
}
ret = shmctl(shmid, 0, IPC_RMID);
if (ret != 0) {
perror("shmctl destory shm error");
}
return 0;
}
int wait = 0;
char * shmptr;
if ((int) (shmptr = (char *) (shmat(shmid, NULL, 0))) == -1) {
perror("shmat error \n");
exit(1);
}
while (1) {
while ((P(semid) == -1)
[解决办法]
(semctl(semid, 0, GETZCNT, arg) > 0)) {
printf("waiting for enter...\n");
wait = 1;
sleep(1);
}
if (wait == 1) {
printf(":%s\n", shmptr);
}
printf("say something:\n");
scanf("%s", shmptr);
while (V(semid) == -1) {
printf("wait transferring \n");
sleep(3);
}
// 发完消息,等待1s再发送消息
sleep(1);
}
// 正常销毁内核对象
ret = semctl(semid, 0, IPC_RMID);
if (ret != 0) {
perror("semctl destory sem error");
}
ret = shmctl(shmid, 0, IPC_RMID);
if (ret != 0) {
perror("shmctl destory shm error");
}
return 0;
}