怎样做中考成绩查询网站,沈阳网站制作公司思路,网站审核照片幕布,专做电子产品评测的网站信号量
信号量描述
信号量是一个特殊的变量#xff0c;一般取正数值。它的值代表允许访问的资源数目#xff0c;获取资源 时#xff0c;需要对信号量的值进行原子减一#xff0c;该操作被称为 P 操作。
当信号量值为 0 时#xff0c;代表没有资源可用#xff0c;P 操作…信号量
信号量描述
信号量是一个特殊的变量一般取正数值。它的值代表允许访问的资源数目获取资源 时需要对信号量的值进行原子减一该操作被称为 P 操作。
当信号量值为 0 时代表没有资源可用P 操作会阻塞。
释放资源时需要对信号量的值进行原子加一该操作被称为 V 操作。
信号量主要用来同步进程。
信号量的值如果只取 0,1将其称为二值信号量。
如果信 号量的值大于 1则称之为计数信号量。
**临界资源同一时刻只允许被一个进程或线程访问的资源 **
**临界区访问临界资源的代码段 **
信号量使用
semget() 创建或者获取已存在的信号量 int semget(key_t key, int nsems, int semflg); semget()成功返回信号量的 ID 失败返回-1 key两个进程使用相同的 key 值就可以使用同一个信号量 nsems内核维护的是一个信号量集在新建信号量时其指定信号量集中信号 量的个数 semflg 可选 IPC_CREAT IPC_EXCL semop()对信号量进行改变做 P 操作或者 V 操作 int semop(int semid, struct sembuf *sops, unsigned nsops); semop()成功返回 0失败返回-1 struct sembuf { unsigned short sem_num; //指定信号量集中的信号量下标 short sem_op; //其值为-1代表 P 操作其值为 1代表 V 操作 short sem_flg; //SEM_UNDO }; semctl()控制信号量 int semctl( int semid, int semnum, int cmd, …); semctl()成功返回 0失败返回-1 semid信号量的ID cmd 选项 SETVAL IPC_RMID union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *_buf; }; 封装一个c文件实现创建一个信号
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/sem.hunion semun
{int val;
};
static int semid -1;
void sem_init()
{semid semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//全新创建信号量,如果存在就失败if ( semid -1 )//失败表示该(key_t)1234)信号已存在{semid semget((key_t)1234,1,0600);//获取已存在的信号量idif ( semid -1){printf(semget err\n);}}else//全新创建成功那么要进行初始化{union semun a;a.val 1;//信号量的初始值if ( semctl(semid,0,SETVAL,a) -1)//设置初始值{printf(semctl err\n);}}
}
void sem_p()
{struct sembuf buf;buf.sem_num 0;buf.sem_op -1; //p操作buf.sem_flg SEM_UNDO;if ( semop(semid,buf,1) -1){printf(semop p err\n);}}
void sem_v()
{struct sembuf buf;buf.sem_num 0;buf.sem_op 1; //v操作buf.sem_flg SEM_UNDO;if ( semop(semid,buf,1) -1){printf(semop v err\n);}
}
void sem_destroy()
{if ( semctl(semid,0,IPC_RMID) -1){printf(semctl destroy err\n);}}假设资源只有一份每轮a进程使用2次 b进程使用3次如何解决。
我们可以使用信号量解决临界资源问题 a进程代码
#include unistd.h
#include stdio.h
#include fcntl.h
#include signal.h
#include stdlib.h
#include string.h
#include signal.h
#include sem.c
int main()
{sem_init();//for(int i 0; i 5; i){//psem_p();printf(a);fflush(stdout);int n rand() % 3;sleep(n);printf(a);fflush(stdout);sem_v();n rand() % 3;sleep(n);}sleep(10);sem_destroy();return 0;
}b进程代码
#include unistd.h
#include stdio.h
#include fcntl.h
#include signal.h
#include stdlib.h
#include string.h
#include signal.h
#include sem.c
int main()
{sem_init();for(int i 0; i 5; i){sem_p();printf(b); int n rand() % 3;sleep(n);printf(bb);fflush(stdout);sem_v();n rand() % 3;sleep(n);}return 0;
}效果如下ab不会同时访问该资源 共享内存
共享内存原理
共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理 内存上申请一块空间多个进程可以将其映射到自己的虚拟地址空间中。所有进程都可以访 问共享内存中的地址就好像它们是由 malloc 分配的一样。如果某个进程向共享内存写入了 数据所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。由于它并未提供 同步机制所以我们通常需要用其他的机制来同步对共享内存的访问。 shemget()创建共享内存 int shmget(key_t key, size_t size, int shmflg); shmget()用于创建或者获取共享内存 shmget()成功返回共享内存的 ID 失败返回-1 key 不同的进程使用相同的 key 值可以获取到同一个共享内存 size 创建共享内存时指定要申请的共享内存空间大小 shmflg: IPC_CREAT IPC_EXCL shmat() 用来创建映射 void * shmat( int shmid, const void *shmaddr, int shmflg); shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上 shmat()成功返回返回共享内存的首地址失败返回 NULL shmaddr一般给 NULL由系统自动选择映射的虚拟地址空间 shmflg 一般给 0 可以给 SHM_RDONLY 为只读模式其他的为读写 shmdt()用来断开映射 int shmdt( const void *shmaddr); shmdt()断开当前进程的 shmaddr 指向的共享内存映射 shmdt()成功返回 0 失败返回-1 shmctl()用来控制共享内存 int shmctl( int shmid, int cmd, struct shmid_ds *buf); shmctl()成功返回 0失败返回-1 cmd IPC_RMID 32. * 测试代码
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/shm.h
#include sys/types.h
#include sys/wait.h
int main()
{int shmid shmget((key_t)1234,sizeof(char)*128,IPC_CREAT|0600);if(shmid -1){printf(shmget error\n);exit(1);}char* p shmat(shmid,NULL,SHM_W);if(p NULL){printf(shmat error\n);exit(2);}while(1){char buff[128]{0};printf(parent input: );fflush(stdout);fgets(buff,127,stdin);if(strncmp(buff,end,3) 0){break;}int pid fork();if(pid -1) break;if(pid ! 0){ strcpy(p,buff);}if(pid 0){char* ptrshmat(shmid,NULL,0);printf(child read: %s\n,ptr);shmdt(ptr);exit(0);}wait(NULL);}shmdt(p);exit(0);
}
结果如图 下面我们用信号量来实现对共享内存的访问。 代码如下
sem.c
#include unistd.h
#include stdio.h
#include fcntl.h
#include signal.h
#include stdlib.h
#include string.h
#include signal.h
#include sys/sem.h#define SEM1 0
#define SEM2 1
union semun
{int val;
};
static int semid -1;void sem_init()
{semid semget((key_t)1234, 2, IPC_CREAT | IPC_EXCL | 0600); // 全新创建信号量,如果存在就失败if (semid -1) // 失败表示已存在{semid semget((key_t)1234, 2, 0600); // 获取已存在的信号量idif (semid -1){printf(semget err\n);}}else // 全新创建成功那么要进行初始化{union semun a;const int ar[2] {1, 0};for (int i 0; i 2; i){a.val i; // 信号量的初始值if (semctl(semid, i, SETVAL, a) -1) // 设置初始值{printf(semctl err\n);}}}
}
void sem_p(int sem)
{struct sembuf buf;buf.sem_num sem;buf.sem_op -1; // pbuf.sem_flg SEM_UNDO;if (semop(semid, buf, 1) -1){printf(semop p err\n);}
}
void sem_v(int sem)
{struct sembuf buf;buf.sem_num sem;buf.sem_op 1; // vbuf.sem_flg SEM_UNDO;if (semop(semid, buf, 1) -1){printf(semop v err\n);}
}
void sem_destroy()
{if (semctl(semid, 0, IPC_RMID) -1){printf(semctl destroy err\n);}
}read.c
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/shm.h
#include sem.cint main()
{int shmid shmget((key_t)1234,128,IPC_CREAT|0600);if ( shmid -1 ){printf(shmget err\n);exit(1);}char * s (char*)shmat(shmid,NULL,0);if ( s (char*)-1){printf(shmat err\n);exit(1);}sem_init();while( 1 ){sem_p(SEM2);if ( strncmp(s,end,3) 0 ){break;}printf(read:%s\n,s);sem_v(SEM1);} shmdt(s);shmctl(shmid,IPC_RMID,NULL);sem_destroy();
}
write.c
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/shm.h
#include sem.cint main()
{int shmid shmget((key_t)1234,128,IPC_CREAT|0600);if ( shmid -1 ){printf(shmget err\n);exit(1);}char* s (char*)shmat(shmid,NULL,0);if ( s (char*)-1) {printf(shmat err\n);exit(1);} sem_init();while( 1 ){printf(input: );char buff[128] {0};fflush(stdout);fgets(buff,128,stdin);sem_p(SEM1);strcpy(s,buff);sem_v(SEM2);if ( strncmp(buff,end,3) 0){break;}}shmdt(s);
}
消息队列 接口介绍
1.msgget() 获取消息队列 int msgget(key_t key, int msqflg); msgget()创建或者获取一个消息队列 msgget()成功返回消息队列 ID失败返回-1 msqflg IPC_CREAT 2.msgsnd()发送信息 int msgsnd( int msqid, const void *msqp, size_t msqsz, int msqflg); msgsnd()发送一条消息消息结构为 struct msgbuf { long mtype; // 消息类型 必须大于 0 必须有 char mtext[1]; // 消息数据 }; msgsnd()成功返回 0 失败返回-1 msqsz 指定 mtext 中有效数据的长度 msqflg一般设置为 0 可以设置 IPC_NOWAIT 3.msgrcv()接收消息 ssize_t msgrcv( int msqid, void *msgp, size_t msqsz, long msqtyp, int msqflg); msgrcv()接收一条消息 msgrcv()成功返回 mtext 中接收到的数据长度 失败返回-1 msqtyp 指定接收的消息类型类型可以为 0忽略类型 msqflg 一般设置为 0 可以设置 IPC_NOWAIT 4.msgctl()控制消息队列 int msgctl( int msqid, int cmd, struct msqid_ds *buf); msgctl()控制消息队列 msgctl()成功返回 0失败返回-1 cmd IPC_RMID 测试代码
msgread.c //从消息队列中读取
#includestdio.h
#includestdlib.h
#includeunistd.h
#includestring.h
#includeassert.h
#includesys/msg.h
struct message
{long type;//固定char msg[16];
};
int main()
{int msgidmsgget((key_t)1234,IPC_CREAT|0600);if(msgid-1){printf(msgget err\n);exit(1);}struct message dt;msgrcv(msgid,dt,16,1,0);//0代表不区分类型printf(read message:%s\n,dt.msg);exit(0);
}msgcreat.c //写入数据
#includestdio.h
#includestdlib.h
#includeunistd.h
#includestring.h
#includeassert.h
#includesys/msg.h
struct message //自定义结构体
{long type;//固定的char msg[16];
};
int main()
{int msgidmsgget((key_t)1234,IPC_CREAT|0600);if(msgid-1){printf(msgget err\n);exit(1);}struct message dt;dt.type1;strcpy(dt.msg,China);msgsnd(msgid,dt,16,0);exit(0);
}自定义的结构体第一个是消息类型读取消息是按类型进行的0为不区分消息类型可以全部读取。
写入到消息队列的数据在内存中除了删除和重启系统不会丢失。