(권장 튜토리얼: PHP 비디오 튜토리얼)
소위 크리티컬 섹션(Critical 섹션이라고도 함)은 공유 데이터에 액세스하고 운영하는 코드 세그먼트입니다.
프로세스 상호 배제: 두 개 이상의 프로세스가 동일한 공유 변수 집합의 중요 영역에 동시에 들어갈 수 없습니다. 즉, 한 프로세스가 중요한 리소스에 액세스하고 다른 프로세스는 액세스하기 전에 기다려야 합니다.
프로세스 동기화: 여러 프로세스 간의 실행 순서를 결정하고 데이터 경쟁 문제를 피하는 방법, 즉 여러 프로세스가 함께 잘 실행되도록 하는 방법을 주로 연구합니다.
소위 동기화는 동시 프로세스/스레드가 일부에 있다는 것을 의미합니다. 포인트는 서로를 기다리고 메시지를 교환해야 할 수 있습니다. 이러한 상호 제한된 대기 및 정보 교환을 프로세스/스레드 동기화라고 합니다.
삶의 동기화의 예를 들자면, 배가 고프고 먹고 싶어 엄마에게 일찍 요리하라고 합니다. 이 말을 듣고 엄마는 요리를 시작하지만 엄마가 요리를 마치기 전에 막아서 기다려야 합니다. 식사가 끝나면 자연스럽게 알림을 받고 식사를 진행할 수 있습니다.
동기화와 상호 배제는 두 가지 다른 개념입니다.
동기화는 "작업 A는 작업 B보다 먼저 실행되어야 합니다", "작업 C는 작업 A와 작업 B가 모두 완료된 후에 실행되어야 합니다" 등과 같습니다.
상호 배제는 "작업 A와 작업 B를 동시에 실행할 수 없습니다"와 같습니다.
세마포 사용: 주로 공용 리소스 개체에 대한 다중 프로세스 또는 다중 스레드 액세스 제어에 사용됩니다. 잠금과 유사하게 다중 프로세스(다중 스레드 동기화) 문제를 해결하고 액세스하기 전에 잠금을 획득하고(획득되지 않은 경우 대기) 액세스 후 잠금을 해제하는 데 사용됩니다.
다중 프로세스/다중 스레드는 일반적으로 동시에 실행됩니다. 공용 리소스에 대한 액세스가 동기화되지 않으면 데이터 손상이 발생하기 쉽습니다.
세마포어는 실제로 프로세스 간의 상호 배제 및 동기화를 달성하는 데 사용되는 정수 카운터입니다. 프로세스 간 통신을 위한 데이터 캐싱.
세마포어는 리소스 수를 나타냅니다. 세마포어를 제어하는 두 가지 원자 연산이 있습니다.
하나는 P 연산입니다. 이 연산은 세마포어
다른 하나는 V 작업입니다. 이 작업은 추가 후 세마포 0이면 현재 차단된 프로세스가 없음을 나타냅니다. 공유 리소스에 들어가기 전에
P 작업이 사용되고 공유 리소스를 떠난 후에 V 작업이 사용됩니다. 쌍으로.
예를 들어, 2개의 자원의 세마포어는 2개의 열차 선로와 동일합니다. PV 연산 프로세스는 다음과 같습니다.
A 열차가 선로에 진입하며, 이는 세마포어의 P 연산과 동일하며, 자원은 는 -1이므로 선로가 하나 남습니다
그리고 또 다른 열차가 다른 선로를 점유하는데, 이는 P 연산, 자원 -1
이때 선로가 없기 때문에 신호등이 빨간색으로 변합니다. 세 번째 열차는 기다려야 합니다
첫 번째 열차는 선로를 떠나며 이는 V 운영과 동일합니다. 이때 선로 자원은 1이고 신호등이 녹색으로 변합니다
세 번째 열차가 찾습니다. 신호등이 녹색으로 바뀌어서 선로에 진입하고, 선로 자원이 0이 되어 신호등이 빨간색으로 바뀐다는 것
이 열차 선로 시스템에서 선로는 공공 자원이고, 각 열차는 실과 같으며, 신호등은 세마포어 역할을 합니다. 세마포어는 잠금의 상호 배제 동작을 구현할 수 있으며 프로세스/스레드 동기화도 구현할 수 있습니다
1) 바이너리 세마포어(바이너리 세마포라고도 함)
이 때 세마포어의 초기 값은 0과 1만 있을 수 있다. (바이너리 세마포어는 뮤텍스 잠금 연산을 구현할 수 있습니다.)
2) 일반/카운팅 세마포
이때 세마포어의 초기값은 음수가 아닌 임의의 숫자가 될 수 있습니다. 분명히 이진 세마포어가 포함되어 있습니다. 위에서 언급한 기차 트랙 예제는 카운팅 세마포어를 사용하여 구현할 수 있습니다. 일반적으로 카운팅 세마포어와 잠금의 차이점은 여러 스레드/프로세스(스레드 수는 카운팅 세마포어의 초기 값에 의해 정의됨)를 허용한다는 것입니다. 공용 리소스를 동시에 운영
일반적으로 여러 프로세스를 개발할 때 세마포어만 사용해야 하는 경우가 있습니다. PHP에서는 공용 리소스에서 여러 프로세스가 작동하더라도 세마포어를 사용하는 경우가 거의 없습니다. 무리 파일 잠금은 주로 상호 배제 작업에 사용됩니다
<?php $file = "num.txt";//定一个空文件 $count =0; file_put_contents($file,$count); $pid = pcntl_fork();//fork 一个进程 if($pid == 0){//子进程执行逻辑 $x = (int)file_get_contents($file);//读取文件内容 //i 循环累加 for($i=0; $i<1000; $i++){ $x = $x + 1; } //写入文件 file_put_contents($file,$x); //子进程退出 exit(0); } //父进程执行逻辑 $x = (int)file_get_contents($file); for($i=0; $i<1000; $i++){ $x = $x+1; } //累加写入 file_put_contents($file,$x);
셸 스크립트 작성 지원
#!/bin/bash for a in {1..1000} do (php demo1.php) b=`cat num.txt` if [ $b != 2000 ] then echo -e "错误$b" fi done
논리적으로 말하면 변수 $에 의해 파일에 기록된 마지막 값입니다. x
는 2000이어야 하지만 안타깝게도 그렇지 않습니다. 따라서 위 스크립트를 실행해 보겠습니다. $x
最后写入文件的值应该是2000,但很不幸,并不是如此,我们对上面的脚本执行一下:
运行了1000次,发现出现了变量$x值结果是 1000 的有8次,虽然发生错误的概率比较小,但是在计算机里是不能容忍的。
为什么会出现这种情况,我们知道单核cpu系统里为了实现多个程序同时运行的假象,操作系统通常都采用时间片调度,一个进程时间片用完就切换下一个进程运行,加上我们的高级语言不是每一行代码都是原子性的,比如x = (int)file_get_contents(
$file)
이런 일이 발생하는 이유는 무엇입니까? 단일 코어 CPU 시스템에서 여러 프로그램이 동시에 실행되는 환상을 달성하기 위해 운영 체제는 일반적으로 한 프로세스의 타임 슬라이스를 사용할 때 타임 슬라이스 스케줄링을 사용합니다. 또한 고급 언어의 모든 코드 줄이 원자적이지는 않습니다. 예를 들어 x = (int)file_get_contents(
$file) code> 이 코드 줄은 우리에게는 분할될 수 없지만 컴파일러에 의해 어셈블리 코드(기계 명령어)로 컴파일되므로 여러 명령어로 구현될 수 있으므로 명령어가 절반만 실행될 경우 문제가 발생합니다. 프로세스에서 할당한 슬라이스가 다른 프로세스에 의해 사용되거나 중단되면 데이터 손상이 발생하여 최종 계산 결과에 오류가 발생할 수 있습니다