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;
}
嘿嘿,你的分數能不能再高點呢