您现在的位置是:主页 > news > 中上网站建设/seo引擎优化外包公司
中上网站建设/seo引擎优化外包公司
admin2025/5/5 20:53:33【news】
简介中上网站建设,seo引擎优化外包公司,个体户怎么做购物网站,家庭电脑做网站信号量 /********************* 信号量就相当于共享内存中的一个盒子, 把信号量初始化成多少就是最开始的时候往盒子里放了多少个信号! P操作就是从盒子里拿信号,只有盒子里有信号时才能拿, 若盒子里没有信号,你就只能…
信号量
/*********************
信号量就相当于共享内存中的一个盒子,
把信号量初始化成多少就是最开始的时候往盒子里放了多少个信号!
P操作就是从盒子里拿信号,只有盒子里有信号时才能拿,
若盒子里没有信号,你就只能在盒子旁边等到什么时候盒子里有信号了,拿到信号才能走!
V操作就是往盒子里放信号,不管盒子里有没有信号,你都可以往里面放信号!
*********************/
一.【信号量是】在计算机中用来模拟信号灯的一个【整数】
当这个整数变为非0才能进行某种操作许可;
在进行操作的同时,将该整数减1,以此改变信号灯,
将减1操作称为P操作,也称获取信号;
当该操作进行完之后,将该整数加1,以此来恢复信号灯,
将加1操作称为V操作,也称释放信号;
信号量的原理可以模拟为一下代码:
int i=N; //初始化信号量
if(i != 0)
{
i--; //可以进行P操作
//i++ //也可以进行V操作
进行某种操作.....
i++; //V操作
}
else if(i == 0)
{
i++; //只能进行V操作
}
二.进程中使用信号量:
1.获取key,使用函数ftok()
key_t key=ftok("/home",'a');
"/home":字符串形式的文件路径,要求必须存在且可访问
'a' :整型的项目ID,要求非0,低8位被使用,一般写一个字符
2.创建/获取信号量,使用函数semget()函数
int semid = semget(key,1,0777 | IPC_CREAT);
key: ftok的返回值
1: 信号量的个数
0777 | IPC_CREAT: 标志,可用 IPC_CREAT IPC_EXCL
注:创建新的信号量时,需要指定权限,如0664 | IPC_CREAT
3.初始化信号量,使用函数semctl()函数
int res = semctl(semid,0,SETVAL,1);
if(res < 0)
{
perror("semctl");
exit(-1);
}
semid:semid,semget的返回值
0:信号量的下标
SETVAL:操作命令
IPC_RMID 删除信号量,不需要第四个参数
IPC_SETVAL 使用第4个参数的值初始化信号量
1:可变参数,是否需要由第三参数决定
4.定义结构体指针
struct sembuf
{
unsigned short sem_num; /* 信号量所在下标 */
short sem_op; /* 具体操作,正数增加,负数减少*/
short sem_flg; /* 标志 IPC_NOWAIT and SEM_UNDO. */
};
5.初始化结构体指针
P操作:
sb.sem_num = 0;
sb.sem_op = -1; //P操作将其初始化为-1
sb.sem_flg = SEM_UNDO;
V操作:
sb.sem_num = 0;
sb.sem_op = 1; //V操作将其初始化为1
sb.sem_flg = SEM_UNDO;
6.操作信号量,使用函数semop()函数
int res = semop(semid,&sb,1);
if(res < 0)
{
perror("semop");
exit(-1);
}
semid:获取的信号量
&sb:结构体指针
struct sembuf
{
unsigned short sem_num; /* 信号量所在下标 */
short sem_op; /* 具体操作,正数增加,负数减少*/
short sem_flg; /* 标志 IPC_NOWAIT and SEM_UNDO. */
};
1:结构体指针指向的结构体数组的元素个数
ps:访问共享资源
7.删除信号量,使用函数semctl()函数
int semctl(semid,0,IPC_RMID);
semid:获取的信号量
0:信号量的下标
IPC_RMID:删除信号量,不需要第四个参数代码实例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>struct sembuf sb;
char *s="exit";
void p(int semid)
{sb.sem_num = 0; sb.sem_op = -1;sb.sem_flg = SEM_UNDO;int res = semop(semid,&sb,1);if(res < 0){perror("sem_op p");exit(-1);}return ;
}
void v(int semid)
{sb.sem_num = 0;sb.sem_op = 1;sb.sem_flg = SEM_UNDO;int res = semop(semid,&sb,1);if(res < 0){perror("sem_op v");exit(-1);}return ;
}
int main()
{//1.生成keykey_t key=ftok("/home",'a');if(key < 0){perror("ftok");exit(-1); //直接结束进程}//2.1 创建信号量int semid = semget(key,1,0777 | IPC_CREAT);if(semid < 0){perror("semget");exit(-1);}//2.2创建共享内存int shmid = shmget(key,4096,0777 | IPC_CREAT);if(shmid < 0){perror("shmget");exit(-1);}//3.1 初始化信号量int res = semctl(semid,0,SETVAL,1);if(res < 0){perror("semctl");exit(-1);} //3.2 映射共享内存void *addr = (void *)shmat(shmid,NULL,0);//0是标志,代表可读可写if(addr == (void *)-1){perror("shmat");exit(-1);} //4.创建进程pid_t pid = fork();if(pid < 0){perror("fork");exit(-1);}else if(pid == 0){ //子进程中接收并打印共享内存中的数据while(1){if(!strcmp(addr,s)){//8.解除子进程的映射shmdt(addr); //9.删除共享内存shmctl(shmid,IPC_RMID,NULL);break;} //6.打印共享内存中数据 p(semid);printf("semid buf = %s\n",(char *)addr);v(semid);}exit(0);}else if(pid > 0){ //父进程中写数据存入共享内存while(1){//5.写数据存入共享内存p(semid);char buf[1024] = {0};scanf("%s",buf); //写数据存入缓存区memcpy(addr,buf,sizeof(buf)); //将缓存区中数据拷贝到共享内存中v(semid);printf("buf = %s\n",buf); //打印要写入的数据if(!strcmp(buf,s)){break;} }//7.解除父进程的映射shmdt(addr);wait(NULL);} return 0;
}
}
三.线程中使用信号量
1.定义一个信号量
sem_t sem;
2.初始化信号量 sem_init()函数
sem_init(&sem,0,1);
&sem: 定义的信号量的地址
第二个参数:0:表示同一进程中的线程间共享,非0:进程间共享
1: 信号量的初始值
注:sem处信号量为同一进程中线程共享的信号量,
信号的初始值为1,即P、V操作从1开始
3.获取信号量(即P操作)
sem_wait(&sem);
&sem:定义的信号量的地址
ps:访问共享资源
4.释放信号量(即V操作)
sem_post(&sem);
&sem:定义的信号量的地址
5.销毁信号量
sem_destroy(&sem);
&sem:定义的信号量的地址代码实例:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
#include <semaphore.h>int count = 0;
sem_t sem;//定义信号量
//线程函数
void *thread_func(void *arg)
{sem_wait(&sem); //获取信号量int *p = (int*)arg; //获得线程创建时传进来的参数int num = *p;printf("child num = %d\n",num);int i;for(i = 0; i < num; i++){count++;}sem_post(&sem); //释放信号量
}
int main()
{int i;int num = 1000000;int res;pthread_t tid[2]; sem_init(&sem,0,1); //初始化信号量 //创建两个线程,线程ID保存在数组tid中for(i = 0; i < 2; i++){res = pthread_create(&tid[i],NULL,thread_func,(void*)&num);if(res != 0){fprintf(stderr,"thread create error: %s\n",strerror(res));exit(-1);}printf("creat new thread id = %lu\n",tid[i]);}//等待线程结束for(i = 0; i < 2; i++){pthread_join(tid[i],NULL);printf("thread %d exited!!\n",i);}printf("count = %d\n",count);sem_destroy(&sem); //不再使用,销毁信号量return 0;
}
【用多个信号量控制访问的先后顺序】:
sem_t sem1;
sem_t sem2;
1.将需要优先访问的线程/进程初始化成非0;
sem_init(&sem1,0,1);
2.将后访问的线程/进程初始化成0;
sem_init(&sem2,0,0);
3.在优先访问的线程/进程的访问过程中对需要后访问的线程/进程
进行V操作
sem_wait(&sem1);
执行任务。。。。。
任务完成
sem_post(&sem2);
4.此时后访问的进程才可以访问,在访问过程中对需要先访问的线程/进程
进行V操作
sem_wait(&sem2);
sem_post(&sem1);
【程序执行流程】:先执行sem1,碰到sem_post(&sem2);后,
sem1休眠,立即执行sem2,碰到sem_post(&sem1);后,
继续执行后面的任务,执行完后再去执行sem1中sem_post(&sem2);后面的程序