导航:首页 > 网络营销 > semget

semget

发布时间:2021-01-15 15:39:42

1、使用信号量实现有限缓冲区的生产者和消费者问题(使用fork(),semget()等函数,能在GCC下运行)

看我下面的代码, 父进程是消费者,子进程是生产者。

REPEATS 决定总共生产的次数 (可以自己修改)
CONSUMER_SPEED 决定消费的速度 (越大越慢,可以自己修改)
PRODUCER_SPEED 决定生产的速度 (越大越慢,可以自己修改)

我的例子里,生产者生产一个随机数。另外消费速度比生产速度慢,所以可以看到输出中,+++ (生产者) 开头的出现的比--- (消费者)多,当生产者结束后,就只有 --- 打印了。

对这个程序由什么问题,可以baidu hi我。在linux/unix下用 gcc 编译。

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>

#define REPEATS (10) /* count of proction/consumption */

#define MAX_BUFFER_SIZE (8)

typedef struct
{
int bottom;
int top;

int data[MAX_BUFFER_SIZE];
} STRUCT_BUFFER;

STRUCT_BUFFER * pBuffer = NULL;

/* Define speed of consumer/procer, change them as u like */
#define PRODUCER_SPEED (1) /* 1/sec */
#define CONSUMER_SPEED (2) /* 1/2sec */

int sem_consume; /* consumer sem */
int sem_proce; /* procer sem */
int shm_buffer; /* shared buffer */

#define FLAG (IPC_CREAT | S_IRWXU)

/* Init semphores & shared buffer */
void init()
{
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;

shm_buffer = shmget(0x1111, sizeof(STRUCT_BUFFER), FLAG);
pBuffer = shmat(shm_buffer, 0, 0);
memset(pBuffer, 0, sizeof(STRUCT_BUFFER));

sem_consume = semget(0x2222, 1, FLAG);
arg.val = 0;
if (semctl(sem_consume, 0, SETVAL, arg) < 0)
{
perror("Consumer");
exit(1);
}

sem_proce = semget(0x3333, 1, FLAG);
arg.val = MAX_BUFFER_SIZE;
if (semctl(sem_proce, 0, SETVAL, arg) < 0)
{
perror("Procer");
exit(1);
}
}

/* destroy semphores & shared buffer */
void deinit()
{
shmctl(shm_buffer, IPC_RMID, NULL);
semctl(sem_consume, 0, IPC_RMID);
semctl(sem_proce, 0, IPC_RMID);
}

int main()
{
int pid, i;
struct sembuf sbuf;

init();

printf("Start fork...\n");
pid = fork();

if (pid > 0)
{
/* parent process, consumer */
for (i = 0; i < REPEATS; i++)
{
/* Try decrementing 1 from consumer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_consume, &sbuf, 1);

/* OK */
printf("Consumer get %6d\n", pBuffer->data[pBuffer->bottom]);
pBuffer->bottom = (pBuffer->bottom+1)%MAX_BUFFER_SIZE;

/* Try incrementing 1 to procer */
sbuf.sem_op = 1;
semop(sem_proce, &sbuf, 1);

sleep(CONSUMER_SPEED);
}
wait(0);
shmdt(pBuffer);
}
else if (pid == 0)
{
srand(time(NULL));
/* child process, procer */
for (i = 0; i < REPEATS; i++)
{
/* Try decrementing 1 from procer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_proce, &sbuf, 1);

/* OK */
pBuffer->data[pBuffer->top] = (rand()%1000)*1000 + i + 1;
printf("Procer put %6d\n", pBuffer->data[pBuffer->top]);
pBuffer->top = (pBuffer->top+1)%MAX_BUFFER_SIZE;

/* Try incrementing 1 to consumer */
sbuf.sem_op = 1;
semop(sem_consume, &sbuf, 1);

sleep(PRODUCER_SPEED);
}
shmdt(pBuffer);
exit(0);
}

deinit();
return 0;
}

2、求助:semget No such file or directory

semget No such file or directory
semget没有这样的文件或目录

3、信号量操作-售票员与乘客

应用程序创建信号量集需要调用semget(2)。系统中每个信号量集由一个semds_id数据结构描述,专其中包属括以下元素:
struct semid_ds {
struct ipc_perm sem_perm; /* operation permission struct */
struct sem *sem_base; /* ptr to first semaphore in set */
ushort_t sem_nsems; /* # of semaphores in set */
#if defined(_LP64)
time_t sem_otime; /* last semop time */
time_t sem_ctime; /* last change time */
#else /*_LP64*/
time_t sem_otime; /* last semop time */
int32_t sem_pad1; /* reserved for time_t expansion */
time_t sem_ctime; /* last change time */

4、对sempo第三个参数nsops怎样理解?请大神详解啊

第2个参数指向元素操作数组 严格来说,应该这样说:第2个参数指向元素操作数组的首地址!!

而有几个信号,只传递一个首地址,函数是不知道的,因此,必须由第三个参数来指出数组元素的个数,即信号量个数!

5、Linux 的P,V操作

他把答案删除了,所以我也得改下了。
--------------------------
semop() 这是个信号函数。

系统调用:semop();
调用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)
EACCESS(权限不够)
EAGAIN(使用了IPC_NOWAIT,但操作不能继续进行)
EFAULT(sops指向的地址无效)
EIDRM(信号量集已经删除)
EINTR(当睡眠时接收到其他信号)
EINVAL(信号量集不存在,或者semid无效)
ENOMEM(使用了SEM_UNDO,但无足够的内存创建所需的数据结构)
ERANGE(信号量值超出范围)
第一个参数是关键字值。第二个参数是指向将要操作的数组的指针。第三个参数是数组中的操作的个数。参数sops指向由sembuf组成的数组。此数组是在linux/sem.h中定义的:
/*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num将要处理的信号量的个数。
sem_op要执行的操作。
sem_flg操作标志。
如果sem_op是负数,那么信号量将减去它的值。这和信号量控制的资源有关。如果没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,直到信号量控制的资源可以使用为止。如果sem_op是正数,则信号量加上它的值。这也就是进程释放信号量控制的资源。最后,如果sem_op是0,那么调用进程将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。
--------------------------

还比如: Semget(),semctl() 等。如有需要解释这些函数,你等加加分哦,我就一一讲解。

6、Linux中semget函数的参数key和函数返回值的作用区别是什么?

key是给内核看的,不同进程用同一个key可以返回一个相同的ID
而返回值是给内核管理用的
二者一一对应,key给应用自由,返回的ID是为了内核管理方便

7、信号量的使用,求助

信号量:一个整数;
大于或等于0时代表可供并发进程使用的资源实体数;
小于0时代表正在等待使用临界区的进程数;
用于互斥的信号量初始值应大于0;
只能通过P、V原语操作而改变;
信号量元素组成:
1、表示信号量元素的值;
2、最后操作信号量元素的进程ID
3、等待信号量元素值+1的进程数;
4、等待信号量元素值为0的进程数;

二、主要函数

1.1 创建信号量
int semget(
key_t key, //标识信号量的关键字,有三种方法:1、使用IPC——PRIVATE让系统产生,
// 2、挑选一个随机数,3、使用ftok从文件路径名中产生
int nSemes, //信号量集中元素个数
int flag //IPC_CREAT;IPC_EXCL 只有在信号量集不存在时创建
)
成功:返回信号量句柄
失败:返回-1

1.2 使用ftok函数根据文件路径名产生一个关键字
key_t ftok(const char *pathname,int proj_id);
路径名称必须有相应权限

1.3 控制信号量
int semctl(
int semid, //信号量集的句柄
int semnum, //信号量集的元素数
int cmd, //命令
/*union senum arg */... //
)
成功:返回相应的值
失败:返回-1

命令详细说明:
cmd: IPC_RMID 删除一个信号量
IPC_EXCL 只有在信号量集不存在时创建
IPC_SET 设置信号量的许可权
SETVAL 设置指定信号量的元素的值为 agc.val
GETVAL 获得一个指定信号量的值
GETPID 获得最后操纵此元素的最后进程ID
GETNCNT 获得等待元素变为1的进程数
GETZCNT 获得等待元素变为0的进程数

union senum 定义如下:
union senum{
int val;
struct semid_ds *buf;
unsigned short * array;
}agc;
其中 semid_ds 定义如下:
struct semid_ds{
struct ipc_pem sem_pem; //operation pemission struct
time_t sem_otime; //last semop()time
time_t sem_ctime; //last time changed by semctl()
struct sem *sembase; //ptr to first semaphore in array
struct sem_queue *sem_pending; //pending operations
struct sem_queue *sem_pending_last; //last pending operations
struct sem_undo *undo; //undo requests on this arrary
unsigned short int sem_nsems; //number of semaphores in set
};

1.4 对信号量 +1 或 -1 或测试是否为0
int semop(
int semid,
struct sembuf *sops, //指向元素操作数组
unsigned short nsops //数组中元素操作的个数
)

结构 sembuf 定义
sembuf{
short int sem_num; //semaphore number
short int sem_op; //semaphore operaion
short int sem_flg //operation flag
};

三、例子:
2.1 服务器

#include <sys/sem.h>
#include <sys/ipc.h>

#define SEGSIZE 1024
#define READTIME 1
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
//生成信号量
int sem_creat(key_t key)
{
union semun sem;
int semid;
sem.val = 0;
semid = semget(key,1,IPC_CREAT|0666);
if (-1 == semid){
printf("create semaphore error\n");
exit(-1);
}
semctl(semid,0,SETVAL,sem);
return semid;
}
//删除信号量
void del_sem(int semid)
{
union semun sem;
sem.val = 0;
semctl(semid,0,IPC_RMID,sem);
}

//p
int p(int semid)
{
struct sembuf sops={0,+1,IPC_NOWAIT};
return (semop(semid,&sops,1));
}
//v
int v(int semid)
{
struct sembuf sops={0,-1,IPC_NOWAIT};
return (semop(semid,&sops,1));
}
int main()
{
key_t key;
int shmid,semid;
char *shm;
char msg[7] = "-data-";
char i;
struct semid_ds buf;

key = ftok("/",0);
shmid = shmget(key,SEGSIZE,IPC_CREAT|0604);
if (-1 == shmid){
printf(" create shared memory error\n");
return -1;
}
shm = (char *)shmat(shmid,0,0);
if (-1 == (int)shm){
printf(" attach shared memory error\n");
return -1;
}
semid = sem_creat(key);
for (i = 0;i <= 3;i++){
sleep(1);
p(semid);
sleep(READTIME);
msg[5] = '0' + i;
memcpy(shm,msg,sizeof(msg));
sleep(58);
v(semid);
}
shmdt(shm);
shmctl(shmid,IPC_RMID,&buf);
del_sem(semid);
return 0;
//gcc -o shm shm.c -g
}

2.2 客户端

#include <sys/sem.h>
#include <time.h>
#include <sys/ipc.h>

#define SEGSIZE 1024
#define READTIME 1
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;

// 打印程序执行时间
void out_time(void)
{
static long start = 0;
time_t tm;
if (0 == start){
tm = time(NULL);
start = (long)tm;
printf(" now start ...\n");
}
printf(" second: %ld \n",(long)(time(NULL)) - start);
}

//创建信号量
int new_sem(key_t key)
{
union semun sem;
int semid;
sem.val = 0;
semid = semget(key,0,0);
if (-1 == semid){
printf("create semaphore error\n");
exit(-1);
}
return semid;
}

//等待信号量变成0
void wait_v(int semid)
{
struct sembuf sops={0,0,0};
semop(semid,&sops,1);
}

int main(void)
{
key_t key;
int shmid,semid;
char *shm;
char msg[100];
char i;

key = ftok("/",0);
shmid = shmget(key,SEGSIZE,0);

if(-1 == shmid){
printf(" create shared memory error\n");
return -1;
}
shm = (char *)shmat(shmid,0,0);
if (-1 == (int)shm){
printf(" attach shared memory error\n");
return -1;
}
semid = new_sem(key);
for (i = 0;i < 3;i ++){
sleep(2);
wait_v(semid);
printf("Message geted is: %s \n",shm + 1);
out_time();
}
shmdt(shm);
return 0;
// gcc -o shmc shmC.c -g
}

8、linux 信号量操作函数

semget()
可以使用系统调用semget()创建一个新的信号量集,或者存取一个已经存在的信号量集:
系统调用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1:errno=EACCESS(没有权限)
EEXIST(信号量集已经存在,无法创建)
EIDRM(信号量集已经删除)
ENOENT(信号量集不存在,同时没有使用IPC_CREAT)
ENOMEM(没有足够的内存创建新的信号量集)
ENOSPC(超出限制)
系统调用semget()的第一个参数是关键字值(一般是由系统调用ftok()返回的)。系统内核将此值和系统中存在的其他的信号量集的关键字值进行比 较。打开和存取操作与参数semflg中的内容相关。IPC_CREAT如果信号量集在系统内核中不存在,则创建信号量集。IPC_EXCL当和 IPC_CREAT一同使用时,如果信号量集已经存在,则调用失败。如果单独使用IPC_CREAT,则semget()要么返回新创建的信号量集的标识 符,要么返回系统中已经存在的同样的关键字值的信号量的标识符。如果IPC_EXCL和IPC_CREAT一同使用,则要么返回新创建的信号量集的标识 符,要么返回-1。IPC_EXCL单独使用没有意义。参数nsems指出了一个新的信号量集中应该创建的信号量的个数。信号量集中最多的信号量的个数是 在linux/sem.h中定义的:
#defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
下面是一个打开和创建信号量集的程序:
intopen_semaphore_set(key_t keyval,int numsems)
{
intsid;
if(!numsems)
return(-1);
if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)
{
return(-1);
}
return(sid);
}
};
==============================================================
semop()
系统调用:semop();
调用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)
EACCESS(权限不够)
EAGAIN(使用了IPC_NOWAIT,但操作不能继续进行)
EFAULT(sops指向的地址无效)
EIDRM(信号量集已经删除)
EINTR(当睡眠时接收到其他信号)
EINVAL(信号量集不存在,或者semid无效)
ENOMEM(使用了SEM_UNDO,但无足够的内存创建所需的数据结构)
ERANGE(信号量值超出范围)
第一个参数是关键字值。第二个参数是指向将要操作的数组的指针。第三个参数是数组中的操作的个数。参数sops指向由sembuf组成的数组。此数组是在linux/sem.h中定义的:
/*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num将要处理的信号量的个数。
sem_op要执行的操作。
sem_flg操作标志。
如果sem_op是负数,那么信号量将减去它的值。这和信号量控制的资源有关。如果没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,直到信号 量控制的资源可以使用为止。如果sem_op是正数,则信号量加上它的值。这也就是进程释放信号量控制的资源。最后,如果sem_op是0,那么调用进程 将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。

9、操作系统作业 抽烟者的问题

/*
* File: PV.h
* Author: Caspar Zhang
*/
#ifndef _PV_H
#define _PV_H

#define SEM_KEY 0x12345678

#define ERR_AND_EXIT(arg) do {
perror(arg);
exit(1);
} while(0)

int P(int semid, int sem_index);
int V(int semid, int sem_index);

#endif /* _PV_H */

/*
* File: PV.c
* Author: Caspar Zhang
*/
#include "PV.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/sem.h>

int P(int semid, int sem_index)
{
struct sembuf buf;

buf.sem_num = sem_index;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;

if (semop(semid, &buf, 1) == -1)
return -1;

return 0;
}

int V(int semid, int sem_index)
{
struct sembuf buf;

buf.sem_num = sem_index;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;

if (semop(semid, &buf, 1) == -1)
return -1;

return 0;
}

/*
* File: Agent.c
* Author: Caspar Zhang
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sem.h>
#include "PV.h"

int main(int argc, char *argv[])
{
/*
* 0 - Paper and matches
* 1 - Matches and tobacco
* 2 - Tobacco and paper
*/
char *ingredient[3] = {
"Paper and matches",
"Matches and tobacco",
"Tobacco and paper"};
int ingred_type;
int semid, i;

srand((unsigned)time(NULL));

/* Puts out the Agent's information */
fprintf(stdout, "I'm the Agent.n" );

/*
* Create a new semaphore set which has 4 semaphores in it.
* The first 3 semaphores are the Smokers' state,
* the last one is the Agent's state
*/
if ((semid = semget(SEM_KEY, 4, IPC_CREAT|0660)) < 0)
ERR_AND_EXIT("semget");
for (i = 0; i < 4; ++i)
if (semctl(semid, i, SETVAL, 0) < 0)
ERR_AND_EXIT("semctl");

/*
* The proceres are shown in below:
* 1. Offer Ingredients
* 2. V(Smoker_i)
* 3. P(Agent)
* 4. Go to 1 and repeat
*/
while (1)
{
/* Offer the ingredients randomly*/
ingred_type = rand() % 3;
fprintf(stdout, "Agent%d: I offered %s, waiting for the smoker.n",
ingred_type, ingredient[ingred_type]);
sleep(5);

/* Wake up the specified smoker */
if (V(semid, ingred_type) < 0) ERR_AND_EXIT("V failed");

/* Wait for smoker to roll and smoke */
if (P(semid, 3) < 0) ERR_AND_EXIT("P failed");
}

return 0;
}

/*
* File: Smoker.c
* Author: Caspar Zhang
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include "PV.h"

int main(int argc, char *argv[])
{
/*
* 0 - Tobacco Smoker
* 1 - Paper Smoker
* 2 - Matches Smoker
*/
char *ingredient[3] = {"Tobacco", "Paper", "Matches"};
int smoker = argv[1][0] - '0';
int semid;

/* Puts out the Smoker's information */
fprintf(stdout, "I'm a smoker. I have %sn", ingredient[smoker]);

/* Get the existed semaphore set */
/* TODO How to create semaphores if smoker process executed first? */
if ((semid = semget(SEM_KEY, 0, 0)) < 0)
ERR_AND_EXIT("semget");
if (semctl(semid, smoker, GETVAL, 0) < 0)
ERR_AND_EXIT("semctl");

/*
* The proceres are shown in below:
* 1. P(Smoker_i)
* 2. Get Ingredients, Roll and Smoke
* 3. V(Agent)
* 4. Go to 1 and repeat
*/
while (1)
{
/* Wait for the Agent*/
fprintf(stdout, "%s: I'm waiting for the agent.n", ingredient[smoker]);
sleep(5);

if (P(semid, smoker) < 0) ERR_AND_EXIT("P failed");

/* Roll and smoke */
fprintf(stdout, "%s: I get the ingredients, I'm rolling and smoking now.n",
ingredient[smoker]);
sleep(5);

/* Wake up Agent */
if (V(semid, 3) < 0) ERR_AND_EXIT("V failed");
}

return 0;
}

嘿嘿,你的分数能不能再高点呢

与semget相关的知识