Dalam swoole, semaphore digunakan terutamanya untuk melindungi sumber yang dikongsi supaya hanya terdapat satu proses pada satu masa apabila nilai semaphore adalah positif, ini bermakna bahawa benang yang diuji boleh dikunci dan digunakan. Semafor Jika nilainya ialah 0, ini bermakna benang yang diuji akan memasuki baris gilir tidur dan menunggu untuk dibangkitkan.
Persekitaran pengendalian tutorial ini: sistem Windows 10, versi Swoole 4, komputer DELL G3
Penggunaan semaphore digunakan terutamanya untuk melindungi sumber yang dikongsi, supaya sumber tersebut dimiliki oleh hanya satu proses (benang)
pada satu masa. Apabila nilai semafor positif, ia bermakna ia terbiar. Benang yang diuji boleh dikunci semasa menggunakannya. Jika 0, ini bermakna ia telah diduduki, dan benang ujian akan memasuki baris gilir tidur dan menunggu untuk dikejutkan.
Linux menyediakan dua jenis semaphore:
(1) Kernel semaphore, digunakan oleh laluan kawalan kernel
(2) Digunakan oleh mod pengguna memproses semaphore, yang dibahagikan kepada semaphore POSIX dan SYSTEM
V semaphore.
Semaphore POSIX dibahagikan kepada semaphore bernama dan semaphore tanpa nama.
Semaphore bernama yang nilainya disimpan dalam fail, jadi ia boleh digunakan untuk benang dan untuk penyegerakan antara proses. Semaphore
tanpa nama yang nilainya disimpan dalam ingatan.
Semafor kernel
Komposisi semafor kernel
Semafor kernel adalah serupa dengan kunci spin, kerana apabila kunci ditutup, ia tidak Membenarkan laluan kawalan kernel untuk meneruskan. Walau bagaimanapun,
Apabila laluan kawalan kernel cuba memperoleh sumber sibuk yang dilindungi oleh kunci semaphore kernel, proses yang sepadan digantung. Hanya apabila sumber dikeluarkan, proses itu boleh dijalankan semula.
Hanya fungsi yang boleh tidur boleh mendapatkan semaphore kernel; baik pengendali mengganggu mahupun fungsi boleh ditangguhkan boleh menggunakan semaphore kernel.
Semaphore kernel ialah objek jenis semaphore struct Dalam rutin di atas
, adalah rawak benang mana yang digunakan untuk sumber semaphore terlebih dahulu. Jika anda mahukan urutan tertentu#include <pthread.h> #include <semaphore.h> #include <sys/types.h> #include <stdio.h> #include <unistd.h> int number; // 被保护的全局变量 sem_t sem_id; void* thread_one_fun(void *arg) { sem_wait(&sem_id); printf("thread_one have the semaphore\n"); number++; printf("number = %d\n",number); sem_post(&sem_id); } void* thread_two_fun(void *arg) { sem_wait(&sem_id); printf("thread_two have the semaphore \n"); number--; printf("number = %d\n",number); sem_post(&sem_id); } int main(int argc,char *argv[]) { number = 1; pthread_t id1, id2; sem_init(&sem_id, 0, 1); pthread_create(&id1,NULL,thread_one_fun, NULL); pthread_create(&id2,NULL,thread_two_fun, NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); printf("main,,,\n"); return 0; }
, anda boleh menggunakan 2 semafor untuk mencapainya. Sebagai contoh, dalam rutin berikut, utas 1 selesai melaksanakan dahulu, dan kemudian utas 2 diteruskan
sehingga ia tamat.
(b) Penyegerakan semaphore yang tidak dinamakan antara proses yang berkaitanint number; // 被保护的全局变量 sem_t sem_id1, sem_id2; void* thread_one_fun(void *arg) { sem_wait(&sem_id1); printf(“thread_one have the semaphore\n”); number++; printf(“number = %d\n”,number); sem_post(&sem_id2); } void* thread_two_fun(void *arg) { sem_wait(&sem_id2); printf(“thread_two have the semaphore \n”); number–; printf(“number = %d\n”,number); sem_post(&sem_id1); } int main(int argc,char *argv[]) { number = 1; pthread_t id1, id2; sem_init(&sem_id1, 0, 1); // 空闲的 sem_init(&sem_id2, 0, 0); // 忙的 pthread_create(&id1,NULL,thread_one_fun, NULL); pthread_create(&id2,NULL,thread_two_fun, NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); printf(“main,,,\n”); return 0; }
Dikatakan sebagai proses yang berkaitan kerana terdapat dua proses dalam program ini, salah satunya proses anak daripada lain. (Dihasilkan oleh
garpu
).
Pada asalnya untuk fork, proses anak hanya mewarisi salinan kod proses induk Mutex hendaklah dua pembolehubah bebas dalam proses induk dan anak
Walau bagaimanapun, apabila mutex dimulakan, pshared = 1 menunjukkan
bahawa mutex berada dalam kawasan memori kongsi, jadi pada masa ini mutex menjadi pembolehubah yang dikongsi oleh proses ibu bapa dan anak. Pada ketika ini, mutex boleh digunakan untuk menyegerakkan proses yang berkaitan.
2. Dinamakan semaphore
#include <semaphore.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char **argv) { int fd, i,count=0,nloop=10,zero=0,*ptr; sem_t mutex; //open a file and map it into memory fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU); write(fd,&zero,sizeof(int)); ptr = mmap( NULL,sizeof(int),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0 ); close(fd); /* create, initialize semaphore */ if( sem_init(&mutex,1,1) < 0) // { perror("semaphore initilization"); exit(0); } if (fork() == 0) { /* child process*/ for (i = 0; i < nloop; i++) { sem_wait(&mutex); printf("child: %d\n", (*ptr)++); sem_post(&mutex); } exit(0); } /* back to parent process */ for (i = 0; i < nloop; i++) { sem_wait(&mutex); printf("parent: %d\n", (*ptr)++); sem_post(&mutex); } exit(0); }
Ciri semaphore bernama adalah untuk menyimpan nilai semaphore dalam fail. Ini menentukan bahawa ia mempunyai julat penggunaan yang sangat luas: ia boleh digunakan untuk urutan, proses berkaitan dan juga proses
yang tidak berkaitan.
(a) Sebab mengapa dinamakan semaphore boleh dikongsi antara proses
Oleh kerana nilai semaphore bernama disimpan dalam fail, untuk proses yang berkaitan, proses anak mewarisinya Fail deskriptor proses
induk, kemudian deskriptor fail yang diwarisi oleh proses anak menghala ke fail yang sama dengan proses induk Apabila
nilai semaphore bernama yang disimpan dalam fail Dikongsi.
(b) Perihalan fungsi yang berkaitan dengan semaphore bernama
Apabila semaphore bernama digunakan, ia berkongsi fungsi sem_wait dan sem_post dengan semaphore yang tidak dinamakan.
Bezanya semaphore yang terkenal menggunakan sem_open dan bukannya sem_init Selain itu, pada akhirnya, semaphore yang terkenal mesti ditutup seperti fail
.
(1) Buka semaphore bernama sedia ada, atau buat dan mulakan semaphore bernama. Satu panggilan melengkapkan penciptaan, permulaan dan tetapan kebenaran semaphore.
sem_t *sem_open(const char *nama, int oflag, mod_t, nilai int);
nama ialah nama laluan bagi fail; O_CREAT|. EXCL mempunyai dua nilai;
mode_t mengawal hak akses semaphore baharu;
Nota:
Nama di sini tidak boleh ditulis dalam format /tmp/aaa.sem, kerana di bawah Linux, sem dicipta
dalam /dev/shm direktori Bawah. Anda boleh menulis nama sebagai "/mysem" atau "mysem", dan fail yang dibuat akan menjadi "/dev/shm/sem.mysem". Juga jangan sekali-kali menulis "/tmp/mysem" atau sesuatu seperti itu.
Apabila oflag = O_CREAT, jika semafor yang dinyatakan mengikut nama tidak wujud, satu akan dibuat dan parameter mod dan nilai
berikut mestilah sah. Jika semaphore yang dinyatakan dengan nama sudah wujud, buka semaphore terus,
dan abaikan mod dan parameter nilai.
Apabila oflag = O_CREAT|O_EXCL, jika semaphore yang dinyatakan mengikut nama sudah wujud, fungsi akan terus mengembalikan ralat
.
(2) Sebaik sahaja anda menggunakan semaphore, adalah penting untuk memusnahkannya.
在做这个之前,要确定所有对这个有名信号量的引用都已经通过sem_close()函数
关闭了,然后只需在退出或是退出处理函数中调用sem_unlink()去删除系统中的信号量,
注意如果有任何的处理器或是线程引用这个信号量,sem_unlink()函数不会起到任何的作
用。
也就是说,必须是最后一个使用该信号量的进程来执行sem_unlick才有效。因为每个
信号灯有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才能把
name所指的信号灯从文件系统中删除。也就是要等待最后一个sem_close发生。
(c)有名信号量在无相关进程间的同步
前面已经说过,有名信号量是位于共享内存区的,那么它要保护的资源也必须是位于
共享内存区,只有这样才能被无相关的进程所共享。
在下面这个例子中,服务进程和客户进程都使用shmget和shmat来获取得一块共享内
存资源。然后利用有名信号量来对这块共享内存资源进行互斥保护。
File1: server.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <semaphore.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define SHMSZ 27 char SEM_NAME[]= "vik"; int main() { char ch; int shmid; key_t key; char *shm,*s; sem_t *mutex; //name the shared memory segment key = 1000; //create & initialize semaphore mutex = sem_open(SEM_NAME,O_CREAT,0644,1); if(mutex == SEM_FAILED) { perror("unable to create semaphore"); sem_unlink(SEM_NAME); exit(-1); } //create the shared memory segment with this key shmid = shmget(key,SHMSZ,IPC_CREAT|0666); if(shmid<0) { perror("failure in shmget"); exit(-1); } //attach this segment to virtual memory shm = shmat(shmid,NULL,0); //start writing into memory s = shm; for(ch='A';ch<='Z';ch++) { sem_wait(mutex); *s++ = ch; sem_post(mutex); } //the below loop could be replaced by binary semaphore while(*shm != '*') { sleep(1); } sem_close(mutex); sem_unlink(SEM_NAME); shmctl(shmid, IPC_RMID, 0); exit(0); } <u>File 2: client.c</u> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <semaphore.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define SHMSZ 27 char SEM_NAME[]= "vik"; int main() { char ch; int shmid; key_t key; char *shm,*s; sem_t *mutex; //name the shared memory segment key = 1000; //create & initialize existing semaphore mutex = sem_open(SEM_NAME,0,0644,0); if(mutex == SEM_FAILED) { perror("reader:unable to execute semaphore"); sem_close(mutex); exit(-1); } //create the shared memory segment with this key shmid = shmget(key,SHMSZ,0666); if(shmid<0) { perror("reader:failure in shmget"); exit(-1); } //attach this segment to virtual memory shm = shmat(shmid,NULL,0); //start reading s = shm; for(s=shm;*s!=NULL;s++) { sem_wait(mutex); putchar(*s); sem_post(mutex); } //once done signal exiting of reader:This can be replaced by another semaphore *shm = '*'; sem_close(mutex); shmctl(shmid, IPC_RMID, 0); exit(0); }
SYSTEM V信号量
这是信号量值的集合,而不是单个信号量。相关的信号量操作函数由
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> static int nsems; static int semflg; static int semid; int errno=0; union semun { int val; struct semid_ds *buf; unsigned short *array; }arg; int main() { struct sembuf sops[2]; //要用到两个信号量,所以要定义两个操作数组 int rslt; unsigned short argarray[80]; arg.array = argarray; semid = semget(IPC_PRIVATE, 2, 0666); if(semid < 0 ) { printf("semget failed. errno: %d\n", errno); exit(0); } //获取0th信号量的原始值 rslt = semctl(semid, 0, GETVAL); printf("val = %d\n",rslt); //初始化0th信号量,然后再读取,检查初始化有没有成功 arg.val = 1; // 同一时间只允许一个占有者 semctl(semid, 0, SETVAL, arg); rslt = semctl(semid, 0, GETVAL); printf("val = %d\n",rslt); sops[0].sem_num = 0; sops[0].sem_op = -1; sops[0].sem_flg = 0; sops[1].sem_num = 1; sops[1].sem_op = 1; sops[1].sem_flg = 0; rslt=semop(semid, sops, 1); //申请0th信号量,尝试锁定 if (rslt < 0 ) { printf("semop failed. errno: %d\n", errno); exit(0); } //可以在这里对资源进行锁定 sops[0].sem_op = 1; semop(semid, sops, 1); //释放0th信号量 rslt = semctl(semid, 0, GETVAL); printf("val = %d\n",rslt); rslt=semctl(semid, 0, GETALL, arg); if (rslt < 0) { printf("semctl failed. errno: %d\n", errno); exit(0); } printf("val1:%d val2: %d\n",(unsigned int)argarray[0],(unsigned int)argarray[1]); if(semctl(semid, 1, IPC_RMID) == -1) { Perror(“semctl failure while clearing reason”); } return(0); }
推荐学习: swoole教程
Atas ialah kandungan terperinci Apakah kegunaan semaphore dalam swole. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!