linux进程间信号量的等待投递

linux进程间信号量的等待投递,第1张

每个信号量都具有一个非负的值,且信号量支持等待和投递操作。系统调用 semop 实现了这两个操作。它的第一个参数是信号量的标识符,第二个参数是一个包含 struct sembuf 类型元素的数组;这些元素指明了您希望执行的操作。第三个参数是这个数组的长度。结构体sembuf中包含如下字段:

sem_num将要执行操作的信号量组中包含的信号量数量。 sem_op是一个指定了操作类型的整数。 如果sem_op是一个正整数,则这个值会立刻被加到信号量的值上。 [BR]如果 sem_op 为负,则将从信号量值中减去它的绝对值。如果这将使信号量的值小于零,则这个操作会导致进程阻塞,直到信号量的值至少等于操作值的绝对值(由其它进程增加它的值)。 [BR]如果 sem_op 为0,这个操作会导致进程阻塞,直到信号量的值为零才恢复。 sem_flg 是一个符号位。指定 IPC_NOWAIT 以防止操作阻塞;如果该操作本应阻塞,则semop调用会失败。如果为sem_flg指定SEM_UNDO,Linux会在进程退出的时候自动撤销该次操作。 代码 5.4 展示了二元信号量的等待和投递操作。

代码 5.4 (sem_pv.c)二元信号量等待和投递操作

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

/* 等待一个二元信号量。阻塞直到信号量的值为正,然后将其减1 */

int binary_semaphore_wait (int semid)

{

struct sembuf operations[1]

/* 使用(且仅使用)第一个信号量 */

operations[0].sem_num = 0

/* 减一。 */

operations[0].sem_op = -1

/* 允许撤销操作 */

operations[0].sem_flg = SEM_UNDO

return semop (semid, operations, 1)

}

/* 对一个二元信号量执行投递操作:将其值加一。 这个操作会立即返回。*/

int binary_semaphore_post (int semid)

{

struct sembuf operations[1]

/* 使用(且仅使用)第一个信号量 */

operations[0].sem_num = 0

/* 加一 */

operations[0].sem_op = 1

/* 允许撤销操作 */

operations[0].sem_flg = SEM_UNDO

return semop (semid, operations, 1)

}

指定 SEM_UNDO 标志解决当出现一个进程仍然持有信号量资源时被终止这种特殊情况时可能出现的资源泄漏问题。当一个进程被有意识或者无意识地结束的时候,信号量的值会被调整到“撤销”了所有该进程执行过的操作后的状态。例如,如果一个进程在被杀死之前减小了一个信号量的值,则该信号量的值会增长。

信号量:一个整数;

大于或等于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 = 0i <= 3i++){

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 = 0i <3i ++){

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

}

linux中的进程通信分为三个部分:低级通信,管道通信和进程间通信IPC(inter process communication)。linux的低级通信主要用来传递进程的控制信号——文件锁和软中断信号机制。linux的进程间通信IPC有三个部分——①信号量,②共享内存和③消息队列。以下是我编写的linux进程通信的C语言实现代码。操作系统为redhat9.0,编辑器为vi,编译器采用gcc。下面所有实现代码均已经通过测试,运行无误。

一.低级通信--信号通信

signal.c

#include

#include

#include

/*捕捉到信号sig之后,执行预先预定的动作函数*/

void sig_alarm(int sig)

{

printf("---the signal received is %d. /n", sig)

signal(SIGINT, SIG_DFL)//SIGINT终端中断信号,SIG_DFL:恢复默认行为,SIN_IGN:忽略信号

}

int main()

{

signal(SIGINT, sig_alarm)//捕捉终端中断信号

while(1)

{

printf("waiting here!/n")

sleep(1)

}

return 0

}

二.管道通信

pipe.c

#include

#define BUFFER_SIZE 30

int main()

{

int x

int fd[2]

char buf[BUFFER_SIZE]

char s[BUFFER_SIZE]

pipe(fd)//创建管道

while((x=fork())==-1)//创建管道失败时,进入循环

/*进入子进程,子进程向管道中写入一个字符串*/

if(x==0)

{

sprintf(buf,"This is an example of pipe!/n")

write(fd[1],buf,BUFFER_SIZE)

exit(0)

}

/*进入父进程,父进程从管道的另一端读出刚才写入的字符串*/

else

{

wait(0)//等待子进程结束

read(fd[0],s,BUFFER_SIZE)//读出字符串,并将其储存在char s[]中

printf("%s",s)//打印字符串

}

return 0

}

三.进程间通信——IPC

①信号量通信

sem.c

#include

#include

#include

#include types.h>

#include ipc.h>

#include sem.h>

/*联合体变量*/

union semun

{

int val//信号量初始值

struct semid_ds *buf

unsigned short int *array

struct seminfo *__buf

}

/*函数声明,信号量定义*/

static int set_semvalue(void)//设置信号量

static void del_semvalue(void)//删除信号量

static int semaphore_p(void)//执行P操作

static int semaphore_v(void)//执行V操作

static int sem_id//信号量标识符

int main(int argc, char *argv[])

{

int i

int pause_time

char op_char = 'O'

srand((unsigned int)getpid())

sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT)//创建一个信号量,IPC_CREAT表示创建一个新的信号量

/*如果有参数,设置信号量,修改字符*/

if (argc >1)

{

if (!set_semvalue())

{

fprintf(stderr, "Failed to initialize semaphore/n")

exit(EXIT_FAILURE)

}

op_char = 'X'

sleep(5)

}

for(i = 0i <10i++)

{

/*执行P操作*/

if (!semaphore_p())

exit(EXIT_FAILURE)

printf("%c", op_char)

fflush(stdout)

pause_time = rand() % 3

sleep(pause_time)

printf("%c", op_char)

fflush(stdout)

/*执行V操作*/

if (!semaphore_v())

exit(EXIT_FAILURE)

pause_time = rand() % 2

sleep(pause_time)

}

printf("/n%d - finished/n", getpid())

if (argc >1)

{

sleep(10)

del_semvalue()//删除信号量

}

exit(EXIT_SUCCESS)

}

/*设置信号量*/

static int set_semvalue(void)

{

union semun sem_union

sem_union.val = 1

if (semctl(sem_id, 0, SETVAL, sem_union) == -1)

return(0)

return(1)

}

/*删除信号量*/

static void del_semvalue(void)

{

union semun sem_union

if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)

fprintf(stderr, "Failed to delete semaphore/n")

}

/*执行P操作*/

static int semaphore_p(void)

{

struct sembuf sem_b

sem_b.sem_num = 0

sem_b.sem_op = -1/* P() */

sem_b.sem_flg = SEM_UNDO

if (semop(sem_id, &sem_b, 1) == -1)

{

fprintf(stderr, "semaphore_p failed/n")

return(0)

}

return(1)

}

/*执行V操作*/

static int semaphore_v(void)

{

struct sembuf sem_b

sem_b.sem_num = 0

sem_b.sem_op = 1/* V() */

sem_b.sem_flg = SEM_UNDO

if (semop(sem_id, &sem_b, 1) == -1)

{

fprintf(stderr, "semaphore_v failed/n")

return(0)

}

return(1)

}

②消息队列通信

send.c

#include

#include

#include

#include

#include

#include types.h>

#include ipc.h>

#include msg.h>

#define MAX_TEXT 512

/*用于消息收发的结构体--my_msg_type:消息类型,some_text:消息正文*/

struct my_msg_st

{

long int my_msg_type

char some_text[MAX_TEXT]

}

int main()

{

int running = 1//程序运行标识符

struct my_msg_st some_data

int msgid//消息队列标识符

char buffer[BUFSIZ]

/*创建与接受者相同的消息队列*/

msgid = msgget((key_t)1234, 0666 | IPC_CREAT)

if (msgid == -1)

{

fprintf(stderr, "msgget failed with error: %d/n", errno)

exit(EXIT_FAILURE)

}

/*向消息队列中发送消息*/

while(running)

{

printf("Enter some text: ")

fgets(buffer, BUFSIZ, stdin)

some_data.my_msg_type = 1

strcpy(some_data.some_text, buffer)

if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1)

{

fprintf(stderr, "msgsnd failed/n")

exit(EXIT_FAILURE)

}

if (strncmp(buffer, "end", 3) == 0)

{

running = 0

}

}

exit(EXIT_SUCCESS)

}

receive.c

#include

#include

#include

#include

#include

#include types.h>

#include ipc.h>

#include msg.h>

/*用于消息收发的结构体--my_msg_type:消息类型,some_text:消息正文*/

struct my_msg_st

{

long int my_msg_type

char some_text[BUFSIZ]

}

int main()

{

int running = 1//程序运行标识符

int msgid//消息队列标识符

struct my_msg_st some_data

long int msg_to_receive = 0//接收消息的类型--0表示msgid队列上的第一个消息

/*创建消息队列*/

msgid = msgget((key_t)1234, 0666 | IPC_CREAT)

if (msgid == -1)

{

fprintf(stderr, "msgget failed with error: %d/n", errno)

exit(EXIT_FAILURE)

}

/*接收消息*/

while(running)

{

if (msgrcv(msgid, (void *)&some_data, BUFSIZ,msg_to_receive, 0) == -1)

{

fprintf(stderr, "msgrcv failed with error: %d/n", errno)

exit(EXIT_FAILURE)

}

printf("You wrote: %s", some_data.some_text)

if (strncmp(some_data.some_text, "end", 3) == 0)

{

running = 0

}

}

/*删除消息队列*/

if (msgctl(msgid, IPC_RMID, 0) == -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed/n")

exit(EXIT_FAILURE)

}

exit(EXIT_SUCCESS)

}

③共享内存通信

share.h

#define TEXT_SZ 2048 //申请共享内存大小

struct shared_use_st

{

int written_by_you//written_by_you为1时表示有数据写入,为0时表示数据已经被消费者提走

char some_text[TEXT_SZ]

}

producer.c

#include

#include

#include

#include

#include types.h>

#include ipc.h>

#include shm.h>

#include "share.h"

int main()

{

int running = 1//程序运行标志位

void *shared_memory = (void *)0

struct shared_use_st *shared_stuff

char buffer[BUFSIZ]

int shmid//共享内存标识符

/*创建共享内存*/

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT)

if (shmid == -1)

{

fprintf(stderr, "shmget failed/n")

exit(EXIT_FAILURE)

}

/*将共享内存连接到一个进程的地址空间中*/

shared_memory = shmat(shmid, (void *)0, 0)//指向共享内存第一个字节的指针

if (shared_memory == (void *)-1)

{

fprintf(stderr, "shmat failed/n")

exit(EXIT_FAILURE)

}

printf("Memory attached at %X/n", (int)shared_memory)

shared_stuff = (struct shared_use_st *)shared_memory

/*生产者写入数据*/

while(running)

{

while(shared_stuff->written_by_you == 1)

{

sleep(1)

printf("waiting for client.../n")

}

printf("Enter some text: ")

fgets(buffer, BUFSIZ, stdin)

strncpy(shared_stuff->some_text, buffer, TEXT_SZ)

shared_stuff->written_by_you = 1

if (strncmp(buffer, "end", 3) == 0)

{

running = 0

}

}

/*该函数用来将共享内存从当前进程中分离,仅使得当前进程不再能使用该共享内存*/

if (shmdt(shared_memory) == -1)

{

fprintf(stderr, "shmdt failed/n")

exit(EXIT_FAILURE)

}

printf("producer exit./n")

exit(EXIT_SUCCESS)

}

customer.c

#include

#include

#include

#include

#include types.h>

#include ipc.h>

#include shm.h>

#include "share.h"

int main()

{

int running = 1//程序运行标志位

void *shared_memory = (void *)0

struct shared_use_st *shared_stuff

int shmid//共享内存标识符

srand((unsigned int)getpid())

/*创建共享内存*/

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT)

if (shmid == -1)

{

fprintf(stderr, "shmget failed/n")

exit(EXIT_FAILURE)

}

/*将共享内存连接到一个进程的地址空间中*/

shared_memory = shmat(shmid, (void *)0, 0)//指向共享内存第一个字节的指针

if (shared_memory == (void *)-1)

{

fprintf(stderr, "shmat failed/n")

exit(EXIT_FAILURE)

}

printf("Memory attached at %X/n", (int)shared_memory)

shared_stuff = (struct shared_use_st *)shared_memory

shared_stuff->written_by_you = 0

/*消费者读取数据*/

while(running)

{

if (shared_stuff->written_by_you)

{

printf("You wrote: %s", shared_stuff->some_text)

sleep( rand() % 4 )

shared_stuff->written_by_you = 0

if (strncmp(shared_stuff->some_text, "end", 3) == 0)

{

running = 0

}

}

}

/*该函数用来将共享内存从当前进程中分离,仅使得当前进程不再能使用该共享内存*/

if (shmdt(shared_memory) == -1)

{

fprintf(stderr, "shmdt failed/n")

exit(EXIT_FAILURE)

}

/*将共享内存删除,所有进程均不能再访问该共享内存*/

if (shmctl(shmid, IPC_RMID, 0) == -1)

{

fprintf(stderr, "shmctl(IPC_RMID) failed/n")

exit(EXIT_FAILURE)

}

exit(EXIT_SUCCESS)

}

摘自:


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/422047.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-25
下一篇2023-05-25

发表评论

登录后才能评论

评论列表(0条)

    保存