<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>В лабиринте извилин &#187; unix</title>
	<atom:link href="http://www.charnad.com/blog/tag/unix/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.charnad.com</link>
	<description>Блог-центр им. CharnaD</description>
	<lastBuildDate>Wed, 18 Jan 2012 14:52:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>PHP: эксклюзивный счетчик в Shared Memory</title>
		<link>http://www.charnad.com/blog/php-eksklyuzivnyj-schetchik-v-shared-memory/</link>
		<comments>http://www.charnad.com/blog/php-eksklyuzivnyj-schetchik-v-shared-memory/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 12:41:14 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[*nix]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ipc]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[shared memory]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=992</guid>
		<description><![CDATA[Я надеюсь что вы уже прочитали вводную статью про многопоточность в PHP, или вам это просто не требуется. Теперь я расскажу про счетчик, который будет доступен для потоков приложения, при этом доступ к нему будет эксклюзивным. Разделяемая память - особая область памяти, которая доступа ВСЕМ процессам операционной системы. Доступ к определенному сегменту можно получить с [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" style="float:left;" src="http://www.charnad.com/blog/wp-content/uploads/pictures/php.gif" alt=""/></p>
<p>Я надеюсь что вы уже прочитали вводную статью про <a href="http://www.charnad.com/blog/mnogopotochnost-na-php/">многопоточность в PHP</a>, или вам это просто не требуется. Теперь я расскажу про счетчик, который будет доступен для потоков приложения, при этом доступ к нему будет эксклюзивным.</p>
<p><span id="more-992"></span></p>
<p>Разделяемая память - особая область памяти, которая доступа ВСЕМ процессам операционной системы. Доступ к определенному сегменту можно получить с помощью двух параметров: имени существующего файла и одного символа, который будет ключом System V IPC. Это нужно для того, чтобы несколько сегментов могли быть выделены основываясь на одном и том же файле. Звучит пока очень туманно, но сейчас я приведу пример, и надеюсь все станет понятно.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t_key</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ftok</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'g'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$shmid</span> <span style="color: #339933;">=</span> <span style="color: #990000;">shmop_open</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$t_key</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'c'</span><span style="color: #339933;">,</span> <span style="color: #208080;">0755</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">64</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">shmop_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$shmid</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">shmop_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$shmid</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Первой командой, специальной функцией ftok мы получили ключ, по которому будем получать доступ к сегменту разделяемой памяти. Первым параметром мы передали ему имя файла скрипта, а вторым букву 'g'. Почему 'g'? А просто так, можно взять любой символ.<br />
Во второй строке мы собственно открываем доступ к сегменту памяти. Первый параметр - наш ключ, второй параметр 'c' - флаг указывающий на то, что мы создаем сегмент памяти, при том, если он уже существуем - он открывается на чтение/запись. Третий параметр - права на доступ, четвертый - размер в байтах.<br />
В третьей строке мы записываем туда единицу, последний параметр - смещение.<br />
И наконец закрываем сегмент.<br />
Теперь по адресу, который определяется файлом скрипта и буквой 'g' в сегменте размером 64 байта лежит единица, и ее может достать любой процесс.</p>
<p>Теперь представим, что у нас программа работает в 50 потоков, она обрабатывает файл строчка за строчкой. Мы не хотим, чтобы программа два раза обрабатывала одну строку, поэтому кладем в разделяемую память номер строки, которая была обработана последней. И каждый процесс перед тем, как считать строчку берет из разделяемой памяти номер последней обработанной строки, прибавляет единицу, записывает обратно в разделяемую память и идет обрабатывать эту строчку. Следующий процесс возьмет уже строчку с номером на один больше. Все хорошо, все радуются, работает быстро. Однако случается так, что два процесса одновременно решили взять значение из памяти и взяли одинаковое значение и записали одинаковое. А представьте, что сразу 50 процессов одновременно считают значение. В общем дело ясное, что нам надо ограничить доступ к памяти одним процессом.</p>
<p>Как раз для таких случаев придуманы семафоры. Семафор (semaphore) - это такая сущность, которая позволяет ограниченному количеству процессов одновременно получать "зеленый свет" на выполнение чего-либо. Семафор, у которого такое количество равно 1 называется мьютексом (mutex). Именно мьютекс позволит нам не допускать в наш сегмент памяти больше одного процесса и остановит анархию.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$sem</span> <span style="color: #339933;">=</span> <span style="color: #990000;">sem_get</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">ftok</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'g'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">sem_acquire</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sem</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//тут может быть только один процесс</span>
<span style="color: #990000;">sem_release</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sem</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Мы получаем ключ для семафора точно таким же образом, как и для разделяемой памяти. Третий параметр - автоматическое "отпускание" семафора, если поток, который был впущен завершился. Те потоки, которые попытаются получить доступ к семафору, будут блокированы до тех пор, пока семафор не освободится. Это похоже на очередь в туалет. Один внутри, остальные снаружи. Один выходит, другой заходит и закрывается, другие продолжают ждать.
</p>
<p>Таким образом, создав ячейку памяти и создав семафор мы получаем счетчик, который позволит нам обрабатывать файл построчно не боясь, что одна строка будет обработана два раза. Для использования этого принципа я сделал класс Counter, который работает в моем многопоточном приложении. Взять его можно <a href="http://pastebin.org/86576">вот здесь</a>. А тут я приведу пример использования:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//Ноль это наше начальное состояние счетчика</span>
<span style="color: #000088;">$counter</span> <span style="color: #339933;">=</span> Counter<span style="color: #339933;">::</span>_new<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'g'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//Порождаем потомков</span>
<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> PROCESS_AMOUNT<span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$pid</span> <span style="color: #339933;">=</span> pcntl_fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pid</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Error spawning new process'</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elseif</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pid</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">//Родительский процесс у нас ничего не будет делать</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">//Первый параметр - имя счетчика, и заодно часть ключа</span>
        <span style="color: #666666; font-style: italic;">//Второй параметр - увеличивать ли значение счетчика</span>
        <span style="color: #666666; font-style: italic;">//В данном случае мы просто читаем значение</span>
        <span style="color: #000088;">$counter</span> <span style="color: #339933;">=</span> Counter<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'g'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">//TOTAL_LINES - количество строк в файле</span>
        <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$counter</span> <span style="color: #339933;">&lt;</span> TOTAL_LINES<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">//Берем значение счетчика и увеличиваем его на 1</span>
            <span style="color: #000088;">$counter</span> <span style="color: #339933;">=</span> Counter<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'g'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">//Обарабатываем файл</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/php-eksklyuzivnyj-schetchik-v-shared-memory/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

