目次
swoole でのセマフォの使い方
ホームページ PHPフレームワーク Swoole swooleでのセマフォの使用法は何ですか

swooleでのセマフォの使用法は何ですか

Mar 14, 2022 pm 03:29 PM
swoole

swoole では、セマフォは主に共有リソースを保護するために使用されるため、リソースには一度に 1 つのプロセスしか存在しません。セマフォの値が正の場合、テスト対象のスレッドをロックできることを意味します。セマフォ 値が 0 の場合、テストされたスレッドがスリープ キューに入り、ウェイクアップされるのを待つことを意味します。

swooleでのセマフォの使用法は何ですか

このチュートリアルの動作環境: Windows10 システム、Swoole4 バージョン、DELL G3 パソコン

swoole でのセマフォの使い方

セマフォの使用は、主に共有リソースを保護するために使用され、リソースが一度に 1 つのプロセス (スレッド) のみによって所有されるようにします。セマフォの値が正の場合、それはアイドル状態であることを意味します。テスト対象のスレッドは、使用中にロックされる可能性があります。 0 の場合は占有されていることを意味し、テスト スレッドはスリープ キューに入り、ウェイクアップされるのを待ちます。

Linux は 2 種類のセマフォを提供します。

(1) カーネル セマフォ。カーネル制御パスによって使用されます。

(2) ユーザー モードによって使用されます。処理セマフォは、POSIX セマフォと SYSTEM

V セマフォに分かれています。

POSIX セマフォは、名前付きセマフォと名前なしセマフォに分けられます。

名前付きセマフォ。その値はファイルに保存されるため、スレッドやプロセス間の同期に使用できます。値がメモリに保存される名前のない

セマフォ。

カーネル セマフォ

カーネル セマフォの構成

カーネル セマフォはスピン ロックに似ています。ロックが閉じられると、カーネル制御パスの続行を許可しません。ただし、

カーネル制御パスがカーネル セマフォ ロックによって保護されているビジー リソースを取得しようとすると、対応するプロセスは一時停止されます。リソースが解放された場合にのみ、プロセスが再び実行可能になります。

スリープ可能な関数のみがカーネル セマフォを取得でき、割り込みハンドラーも遅延可能関数も内部

コア セマフォを使用できません。

カーネル セマフォは struct セマフォ タイプのオブジェクトです。上記のルーチン

#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;
}
ログイン後にコピー

では、どのスレッドが最初にセマフォ リソースを適用するかはランダムです。特定のシーケンスが必要な場合は、2 つのセマフォを使用してそれを実現できます。たとえば、次のルーチンでは、スレッド 1 が最初に実行を終了し、次にスレッド 2 が終了するまで

を継続します。

int 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;
}
ログイン後にコピー

(b) 関連プロセス間の名前のないセマフォの同期

このプログラムには 2 つのプロセスがあり、一方が他方の子プロセスであるため、関連プロセスであると言われます (

フォーク

制作)。

元々 fork では、子プロセスは親プロセスのコード コピーのみを継承します。ミューテックスは親プロセスと子プロセスの 2 つの独立した変数である必要があります

。ただし、ミューテックスが初期化されると、pshared になります。 = 1 は、ミューテックスが共有メモリ領域にあることを示します。このとき、ミューテックスは親プロセスと子プロセスで共有される変数になります。この時点で、ミューテックスを使用して関連プロセスを同期できます。

rreeee

2.名前付きセマフォ

名前付きセマフォの特徴は、セマフォの値をファイルに保存することです。

これにより、非常に幅広い用途があることがわかります。スレッド、関連プロセス、さらには無関係の

プロセスにも使用できます。 (a) 名前付きセマフォをプロセス間で共有できる理由

名前付きセマフォの値はファイルに格納されているため、子プロセスはそれを関連プロセスに継承します。親プロセスのファイル記述子を継承すると、子プロセスが継承したファイル記述子は親プロセスと同じファイルを指します。もちろん、ファイルに保存された名前付きセマフォ値は共有されます。

(b) 名前付きセマフォに関する関数の説明

名前付きセマフォを使用する場合、sem_wait 関数および sem_post 関数は、名前なしセマフォと共有されます。

違いは、名前付きセマフォが sem_init ではなく sem_open を使用することです。さらに、最後に名前付きセマフォをファイルのように閉じる必要があります。

(1) 既存の名前付きセマフォを開くか、名前付きセマフォを作成して初期化します。 1 回の呼び出しで、セマフォの作成、初期化、権限の設定が完了します。

sem_t *sem_open(const char *name, int oflag, mode_t mode, int value);

name はファイルのパス名です;

Oflag には O_CREAT またはO_CREAT| EXCL には 2 つの値があります。

mode_t は新しいセマフォのアクセス権を制御し、

Value はセマフォの初期化値を指定します。

注:

Linux では、sem は /dev/shm に

作成されるため、ここでの名前を /tmp/aaa.sem の形式で記述することはできません。ディレクトリダウン。名前は「/mysem」または「mysem」と記述すると、作成されるファイルは「/dev/shm/sem.mysem」となりますので、パスは記述しないでください。また、「/tmp/mysem」などは決して書かないでください。

oflag = O_CREAT の場合、name で指定されたセマフォが存在しない場合はセマフォが作成され、次の

mode パラメーターと value パラメーターが有効である必要があります。名前で指定されたセマフォがすでに存在する場合は、セマフォを直接開き、

、モードと値のパラメーターを無視します。

oflag = O_CREAT|O_EXCL の場合、名前で指定されたセマフォがすでに存在する場合、関数は直接

error を返します。

(2) セマフォを使用したら、それを破棄することが重要です。

在做这个之前,要确定所有对这个有名信号量的引用都已经通过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=&#39;A&#39;;ch<=&#39;Z&#39;;ch++)
{
sem_wait(mutex);
*s++ = ch;
sem_post(mutex);
}
//the below loop could be replaced by binary semaphore
while(*shm != &#39;*&#39;)
{
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 = &#39;*&#39;;
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教程

以上がswooleでのセマフォの使用法は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Laravelでswooleコルーチンを使用する方法 Laravelでswooleコルーチンを使用する方法 Apr 09, 2024 pm 06:48 PM

Laravel で Swoole コルーチンを使用すると、大量のリクエストを同時に処理でき、次のような利点があります: 同時処理: 複数のリクエストを同時に処理できます。高いパフォーマンス: Linux の epoll イベント メカニズムに基づいて、リクエストを効率的に処理します。低リソース消費: 必要なサーバー リソースが少なくなります。統合が簡単: Laravel フレームワークとのシームレスな統合が可能で、使いやすいです。

Swoole を使用して高性能 HTTP リバース プロキシ サーバーを実装する方法 Swoole を使用して高性能 HTTP リバース プロキシ サーバーを実装する方法 Nov 07, 2023 am 08:18 AM

Swoole を使用して高性能 HTTP リバース プロキシ サーバーを実装する方法 Swoole は、PHP 言語に基づいた高性能、非同期、同時ネットワーク通信フレームワークです。一連のネットワーク機能を提供し、HTTP サーバー、WebSocket サーバーなどの実装に使用できます。この記事では、Swoole を使用して高性能 HTTP リバース プロキシ サーバーを実装する方法と、具体的なコード例を紹介します。環境構成 まず、サーバーに Swoole 拡張機能をインストールする必要があります

スウールとワーカーマンはどちらが良いですか? スウールとワーカーマンはどちらが良いですか? Apr 09, 2024 pm 07:00 PM

Swoole と Workerman はどちらも高性能の PHP サーバー フレームワークです。 Swoole は、非同期処理、優れたパフォーマンス、スケーラビリティで知られており、多数の同時リクエストと高スループットを処理する必要があるプロジェクトに適しています。 Workerman は、使いやすさや同時実行量が少ないプロジェクトに適した直感的な API を備え、非同期モードと同期モードの両方の柔軟性を提供します。

swoole_process ではユーザーがどのように切り替えられるのでしょうか? swoole_process ではユーザーがどのように切り替えられるのでしょうか? Apr 09, 2024 pm 06:21 PM

Swoole プロセスではユーザーを切り替えることができます。具体的な手順は、プロセスの作成、プロセス ユーザーの設定、プロセスの開始です。

swoole と java ではどちらの方がパフォーマンスが優れていますか? swoole と java ではどちらの方がパフォーマンスが優れていますか? Apr 09, 2024 pm 07:03 PM

パフォーマンスの比較: スループット: Swoole は、コルーチン メカニズムのおかげでスループットが高くなります。レイテンシー: Swoole のコルーチン コンテキスト スイッチングは、オーバーヘッドが低く、レイテンシーが小さくなります。メモリ消費量: Swoole のコルーチンが占有するメモリは少なくなります。使いやすさ: Swoole は、より使いやすい同時プログラミング API を提供します。

swooleフレームワークでサービスを再起動する方法 swooleフレームワークでサービスを再起動する方法 Apr 09, 2024 pm 06:15 PM

Swoole サービスを再起動するには、次の手順に従います。 サービスのステータスを確認し、PID を取得します。サービスを停止するには、「kill -15 PID」を使用します。サービスの開始に使用したのと同じコマンドを使用してサービスを再起動します。

Swoole の動作: 同時タスク処理にコルーチンを使用する方法 Swoole の動作: 同時タスク処理にコルーチンを使用する方法 Nov 07, 2023 pm 02:55 PM

Swoole の動作: 同時タスク処理にコルーチンを使用する方法 はじめに 日常の開発では、複数のタスクを同時に処理する必要がある状況によく遭遇します。従来の処理方法は、マルチスレッドまたはマルチプロセスを使用して同時処理を実現することでしたが、この方法にはパフォーマンスとリソース消費の点で特定の問題がありました。スクリプト言語である PHP は通常、タスクを処理するためにマルチスレッドまたはマルチプロセス メソッドを直接使用できません。ただし、Swoole コルーチン ライブラリの助けを借りて、コルーチンを使用して高パフォーマンスの同時タスク処理を実現できます。この記事で紹介するのは

Swoole Advanced: サーバーの CPU 使用率を最適化する方法 Swoole Advanced: サーバーの CPU 使用率を最適化する方法 Nov 07, 2023 pm 12:27 PM

Swoole は高性能 PHP ネットワーク開発フレームワークであり、その強力な非同期メカニズムとイベント駆動型機能により、高同時実行性と高スループットのサーバー アプリケーションを迅速に構築できます。ただし、ビジネスが拡大し続け、同時実行の量が増加すると、サーバーの CPU 使用率がボトルネックになり、サーバーのパフォーマンスと安定性に影響を与える可能性があります。したがって、この記事では、Swoole サーバーのパフォーマンスと安定性を向上させながらサーバーの CPU 使用率を最適化する方法を紹介し、具体的な最適化コード例を示します。 1つ、

See all articles