<?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; sleepon lock</title>
	<atom:link href="http://www.speedvi.net/tag/sleepon-lock/feed" rel="self" type="application/rss+xml" />
	<link>http://www.speedvi.net</link>
	<description>为者常成 行者常至</description>
	<lastBuildDate>Sat, 12 Jun 2010 06:30:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>用于线程同步的Sleepon锁</title>
		<link>http://www.speedvi.net/2010/02/23/208.html</link>
		<comments>http://www.speedvi.net/2010/02/23/208.html#comments</comments>
		<pubDate>Tue, 23 Feb 2010 07:52:23 +0000</pubDate>
		<dc:creator>行者</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[sleepon lock]]></category>
		<category><![CDATA[同步]]></category>
		<category><![CDATA[线程]]></category>

		<guid isPermaLink="false">http://www.speedvi.net/2010/02/23/208.html</guid>
		<description><![CDATA[　　在多线程程序中常遇到的另外一个情况就是让线程等待某件事的发生。这件事可以是任何事。它可以是设备上的数据就绪了，也可以是传送带到达了合适的位置或数据已经写入磁盘了，等等。另外还要讨论一下多个线程等待某个事件的情况。 　　为了实现这个功能，我们可以使用条件变量(condition variable)或是更简单的睡眠锁(sleepon lock)。 　　要使用睡眠锁，你需要执行几个操作。先看看要调用的函数，之后再看看你该如何使用这个锁： &#160; int pthread_sleepon_lock (void); int pthread_sleepon_unlock (void); int pthread_sleepon_broadcast (void *addr); int pthread_sleepon_signal (void *addr); int pthread_sleepon_wait (void *addr); 　　在这里不要被这些函数的pthread前缀所误导，以为它们是POSIX函数，它们其实不是POSIX函数。 　　如上面所述，一个线程需要等待某件事发生。上面列出的函数中pthread_sleepon_wait()函数应该就是最直接的选择。但是，在你的程序中，这个线程先要检查它是否需要等待。先举例说明，一个线程是生产者线程，它从硬件读取数据，另外一个线程是消费者线程，它对新到来的数据做某种处理。下面先看看消费者线程： volatile int data_ready = 0; consumer () { while (1) { while (!data_ready) { // WAIT } // process data } } 　　这个线程一直在其主处理循环(那个while(1)循环)中，它准备永远做这个工作。它做的第一件事就是查看那个data_ready标志量。如果这个量为0，就表示没有就绪的数据。这样的话，这个线程就进入等待状态。有些时候，生产者线程会唤醒它，之后这个消费者线程会重新检查data_ready这个标志量。假设这就是真实发生的，消费者线程检查标志量并确认为1，也就是数据已经就绪了。之后消费者线程开始处理数据，并检查是否有更多的工作可做，如此往复。 　　在这里我们会有一个问题。就是消费者线程与生产者线程在同步模式下是如何重置这个data_ready标志量的？显然，我们需要对这个标志量有某种独占式的访问以使其在任意时刻只有一个线程能修改它。在这里我们是使用互斥体为基础实现的，不过这个互斥体的实现是封装在sleepon的库函数中的，在这里我们只能使用两个函数：pthread_sleepon_lock()与pthread_sleepon_unlock()来访问它。下面是修改后的消费者线程的代码： consumer () { while (1) [...]


Related posts:<ol><li><a href='http://www.speedvi.net/2010/02/24/211.html' rel='bookmark' title='用于线程同步的条件变量(Condition Variables)'>用于线程同步的条件变量(Condition Variables)</a> <small>　　条件变量(condition variables或condvars)与前面讲的睡眠锁(sleepon lock)非常类似。而实际上睡眠锁是在条件变量的基础上构建的，这也是为什么我们在睡眠锁的例子的解释表中有一个CONDVAR状态。它也能通过不停的调用pthread_cond_wait()函数来释放互斥体、等待以及重新获取互斥体，和pthread_sleepon_wait()函数一样。 　　下面我们就略过初始化的步骤，并使用条件变量来重新完成sleepon部分的那个生产者与消费者的多线程的程序。之后再讨论调用的函数。 &nbsp; /* * cp1.c */ #include...</small></li>
<li><a href='http://www.speedvi.net/2010/01/18/191.html' rel='bookmark' title='线程的启动'>线程的启动</a> <small>　　任何线程在同一个进程中都可以创建另一个线程，这没有任何的限制。创建线程最常用的就是POSIX函数pthread_create()，该函数的定义如下： #include &lt;pthread.h&gt; int pthread_create (pthread_t *thread, const pthread_attr_t *attr,...</small></li>
<li><a href='http://www.speedvi.net/2010/01/27/195.html' rel='bookmark' title='多线程中壁垒(barrier)的使用'>多线程中壁垒(barrier)的使用</a> <small>　　前面我们讲过main()函数与工作线程结束进行的同步，在那里提到了两种方式：pthread_join()函数以及壁垒(barrier)。 　　现在我们回到房子的比喻，假设这个家庭准备到哪个地方旅行。司机上了小货车并发动了引擎。之后，司机就开始等待。只有全部的家庭成员都上车之后，这个小货车才会开动——因为我们不想把任何人落下！ 　　这和我们在前面说的那个绘图程序的原理是一模一样的。主线程要等待全部工作线程结束后，才执行下一步的程序。 　　不过和这个比喻还有一个很大的差别。那就是通过使用pthread_join()函数，我们是等待所有工作线程的结束。也就是说，之后这些线程已经不存在了，它们退出了。 　　通过使用壁垒(barrier)，我们可以等待某些数量的线程在壁垒处集合。在设定的数目达到之后，我们解锁这些线程，让它们继续运行。 　　你先要使用pthread_barrier+init()函数来创建壁垒： #include &lt;pthread.h&gt; int pthread_barrier_init...</small></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>　　在多线程程序中常遇到的另外一个情况就是让线程等待某件事的发生。这件事可以是任何事。它可以是设备上的数据就绪了，也可以是传送带到达了合适的位置或数据已经写入磁盘了，等等。另外还要讨论一下多个线程等待某个事件的情况。</p>
<p>　　为了实现这个功能，我们可以使用条件变量(condition variable)或是更简单的睡眠锁(sleepon lock)。</p>
<p>　　要使用睡眠锁，你需要执行几个操作。先看看要调用的函数，之后再看看你该如何使用这个锁：</p>
<p><span id="more-208"></span>
<p>&nbsp;</p>
<pre class="codesamp">int
pthread_sleepon_lock (void);

int
pthread_sleepon_unlock (void);

int
pthread_sleepon_broadcast (void *<i class="var">addr</i>);

int
pthread_sleepon_signal (void *<i class="var">addr</i>);

int
pthread_sleepon_wait (void *<i class="var">addr</i>);</pre>
<p>　　在这里不要被这些函数的pthread前缀所误导，以为它们是POSIX函数，它们其实不是POSIX函数。</p>
<p>　　如上面所述，一个线程需要等待某件事发生。上面列出的函数中pthread_sleepon_wait()函数应该就是最直接的选择。但是，在你的程序中，这个线程先要检查它是否需要等待。先举例说明，一个线程是生产者线程，它从硬件读取数据，另外一个线程是消费者线程，它对新到来的数据做某种处理。下面先看看消费者线程：</p>
<pre class="codesamp">volatile int data_ready = 0;

consumer ()
{
    while (1) {
        while (!data_ready) {
            // WAIT
        }
        // process data
    }
}</pre>
<p>　　这个线程一直在其主处理循环(那个while(1)循环)中，它准备永远做这个工作。它做的第一件事就是查看那个data_ready标志量。如果这个量为0，就表示没有就绪的数据。这样的话，这个线程就进入等待状态。有些时候，生产者线程会唤醒它，之后这个消费者线程会重新检查data_ready这个标志量。假设这就是真实发生的，消费者线程检查标志量并确认为1，也就是数据已经就绪了。之后消费者线程开始处理数据，并检查是否有更多的工作可做，如此往复。</p>
<p>　　在这里我们会有一个问题。就是消费者线程与生产者线程在同步模式下是如何重置这个data_ready标志量的？显然，我们需要对这个标志量有某种独占式的访问以使其在任意时刻只有一个线程能修改它。在这里我们是使用互斥体为基础实现的，不过这个互斥体的实现是封装在sleepon的库函数中的，在这里我们只能使用两个函数：pthread_sleepon_lock()与pthread_sleepon_unlock()来访问它。下面是修改后的消费者线程的代码：</p>
<pre class="codesamp">consumer ()
{
    while (1) {
        pthread_sleepon_lock ();
        while (!data_ready) {
            // WAIT
        }
        // process data
        data_ready = 0;
        pthread_sleepon_unlock ();
    }
}</pre>
<p>　　现在我们在消费者线程里面田间了锁定与解锁操作。这就意味着消费者线程可以可靠的检查data_ready标志量，而不会受到线程竞争的影响，同时也可以可靠的复位这个标志量。</p>
<p>　　不错吧！那么等待调用该如何处理呢？如我们上面建议的，使用pthread_sleepon_wait()函数。下面是我们的第二个while循环：</p>
<pre class="codesamp">        while (!data_ready) {
            pthread_sleepon_wait (&amp;data_ready);
        }</pre>
<p>　　这个pthread_sleepon_wait()函数实际上做了三步不同的操作：</p>
<ol>
<li>解锁sleepon库函数的互斥体；</li>
<li>执行等待操作；</li>
<li>重新锁定sleepon库函数的互斥体。</li>
</ol>
<p>　　它必须解锁与锁定sleepon库函数互斥体的理由很简单：由于使用互斥体的目的就是确保data_ready标志量的互斥性，也就是说我们在检查这个变量的值的时候就要将生产者线程锁定在外以防止其修改这个变量。不过，如果我们不做解锁的操作的话，生产者线程将永远也没有机会修改这个变量来告诉我们数据已经就绪了。而最后的重新锁定操作是纯粹为了方便起见，这样的话，pthread_sleepon_wait()的用户就没有必要在其唤醒的时候担心这个锁的状态。</p>
<p>　　下面转到生产者线程这里，看看它是如何使用sleepon函数库的。下面是其完整实现：</p>
<pre class="codesamp">producer ()
{
    while (1) {
        // wait for interrupt from hardware here...
        pthread_sleepon_lock ();
        data_ready = 1;
        pthread_sleepon_signal (&amp;data_ready);
        pthread_sleepon_unlock ();
    }
}</pre>
<p>　　可以看到，生产者线程同样也锁定了互斥体，以让其对data_ready标志量可以独占访问以设置其值。需要注意的是这里不是将1写入data_ready变量来唤醒客户的，而是pthread_sleepon_signal()函数唤醒的。</p>
<p>　　下面看看具体都发生了什么。我们对两个线程状态的缩写含义如下表所示：</p>
<table border="1" width="100%">
<tbody>
<tr>
<th>State </th>
<th>Meaning</th>
</tr>
<tr>
<td>CONDVAR </td>
<td>Waiting for the underlying condition variable associated with the sleepon</td>
</tr>
<tr>
<td>MUTEX </td>
<td>Waiting for a mutex</td>
</tr>
<tr>
<td>READY </td>
<td>Capable of using, or already using, the CPU</td>
</tr>
<tr>
<td>INTERRUPT </td>
<td>Waiting for an interrupt from the hardware</td>
</tr>
</tbody>
</table>
<p>　　具体过程如下：</p>
<table border="1" width="100%">
<tbody>
<tr>
<th>Action </th>
<th>Mutex owner </th>
<th>Consumer state </th>
<th>Producer state</th>
</tr>
<tr>
<td>Consumer locks mutex </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Consumer examines <i class="var">data_ready</i> </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Consumer calls <i class="func">pthread_sleepon_wait()</i> </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td><i class="func">pthread_sleepon_wait()</i> unlocks mutex </td>
<td>Free </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td><i class="func">pthread_sleepon_wait()</i> blocks </td>
<td>Free </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Time passes </td>
<td>Free </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Hardware generates data </td>
<td>Free </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Producer locks mutex </td>
<td>Producer </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Producer sets <i class="var">data_ready</i> </td>
<td>Producer </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Producer calls <i class="func">pthread_sleepon_signal()</i> </td>
<td>Producer </td>
<td><span class="const">CONDVAR</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Consumer wakes up, <i class="func">pthread_sleepon_wait()</i> tries to lock mutex </td>
<td>Producer </td>
<td><span class="const">MUTEX</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Producer releases mutex </td>
<td>Free </td>
<td><span class="const">MUTEX</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Consumer gets mutex </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Consumer processes data </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">READY</span></td>
</tr>
<tr>
<td>Producer waits for more data </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Time passes (consumer processing) </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Consumer finishes processing, unlocks mutex </td>
<td>Free </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
<tr>
<td>Consumer loops back to top, locks mutex </td>
<td>Consumer </td>
<td><span class="const">READY</span> </td>
<td><span class="const">INTERRUPT</span></td>
</tr>
</tbody>
</table>
<p>　　表中的最后一条重复了第一条，我们到此已经完成了一个整个的循环。</p>
<p>　　data_ready变量的目的是什么呢？它实际上有两个目的：</p>
<ul>
<li>它是消费者与生产者线程之间的状态标志，用来标识系统状态。如果其为1，就表示有数据可用于处理；如果其为0，就表示没有数据，并且消费者线程应该处于阻塞状态；</li>
<li>它同时也是sleepon同步发生的地方。正式点说，data_ready的地址被作为唯一标识来使用，而它则作为sleepon锁的汇合对象。我们也可以使用(void *) 12345而不是&amp;data_ready，只要这个标识是唯一与一致的，sleepon函数库是不管的。实际上，使用进程中一个变量的地址能够保证生成一个在进程中唯一的数字，当然了在一个进程中也不可能有两个变量使用同一个地址。</li>
</ul>


<p>Related posts:<ol><li><a href='http://www.speedvi.net/2010/02/24/211.html' rel='bookmark' title='用于线程同步的条件变量(Condition Variables)'>用于线程同步的条件变量(Condition Variables)</a> <small>　　条件变量(condition variables或condvars)与前面讲的睡眠锁(sleepon lock)非常类似。而实际上睡眠锁是在条件变量的基础上构建的，这也是为什么我们在睡眠锁的例子的解释表中有一个CONDVAR状态。它也能通过不停的调用pthread_cond_wait()函数来释放互斥体、等待以及重新获取互斥体，和pthread_sleepon_wait()函数一样。 　　下面我们就略过初始化的步骤，并使用条件变量来重新完成sleepon部分的那个生产者与消费者的多线程的程序。之后再讨论调用的函数。 &nbsp; /* * cp1.c */ #include...</small></li>
<li><a href='http://www.speedvi.net/2010/01/18/191.html' rel='bookmark' title='线程的启动'>线程的启动</a> <small>　　任何线程在同一个进程中都可以创建另一个线程，这没有任何的限制。创建线程最常用的就是POSIX函数pthread_create()，该函数的定义如下： #include &lt;pthread.h&gt; int pthread_create (pthread_t *thread, const pthread_attr_t *attr,...</small></li>
<li><a href='http://www.speedvi.net/2010/01/27/195.html' rel='bookmark' title='多线程中壁垒(barrier)的使用'>多线程中壁垒(barrier)的使用</a> <small>　　前面我们讲过main()函数与工作线程结束进行的同步，在那里提到了两种方式：pthread_join()函数以及壁垒(barrier)。 　　现在我们回到房子的比喻，假设这个家庭准备到哪个地方旅行。司机上了小货车并发动了引擎。之后，司机就开始等待。只有全部的家庭成员都上车之后，这个小货车才会开动——因为我们不想把任何人落下！ 　　这和我们在前面说的那个绘图程序的原理是一模一样的。主线程要等待全部工作线程结束后，才执行下一步的程序。 　　不过和这个比喻还有一个很大的差别。那就是通过使用pthread_join()函数，我们是等待所有工作线程的结束。也就是说，之后这些线程已经不存在了，它们退出了。 　　通过使用壁垒(barrier)，我们可以等待某些数量的线程在壁垒处集合。在设定的数目达到之后，我们解锁这些线程，让它们继续运行。 　　你先要使用pthread_barrier+init()函数来创建壁垒： #include &lt;pthread.h&gt; int pthread_barrier_init...</small></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.speedvi.net/2010/02/23/208.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

