关于 pthread cond 的注意事项

最近在使用 pthread condition variable 的时候出现了问题,经过排查发现是 pthread_cond_signal() 放在了 pthread_mutex_unlock() 之后调用导致的。本来不是个什么复杂的问题,但是由于自己一直以来的忽略,觉得有必要记录一下。

先来看下很多文章中都用到的关于 pthread_cond_ 系列函数的例子:

/* ----- producer ----- */

pthread_mutex_lock(&mutex);               /* 1 */
queue.push(item);                         /* 2 */
pthread_cond_signal(&cond);               /* 3 */
pthread_mutex_unlock(&mutex);             /* 4 */

/* ----- consumer ----- */

pthread_mutex_lock(&mutex);               /* 

阅读全文…

pthread 学习笔记 (4)

自旋锁

除了前面提到过的互斥锁和读写锁外,还有另外一种锁:自旋锁(spinlock)。自旋锁的原理比较简单,就是当某个资源不可用时不断查询,直到资源可用:

void tese_and_set(bool* condition)
{
    bool tmp = *condition;
    *condition = true;
    return tmp;
}

void func()
{
    while (test_and_set(&condition));

    /* visit */

    condition = false;
}

其中的操作 test_and_set() 可以看成一个原子操作,通常由硬件来实现。如果 condition 为 false,while 循环会不断地查询 condition 的状态,直到其可用为止。因为在条件不满足时程序也一直在忙,这样会消耗 cpu 资源,所以自旋锁适合用在执行时间不长的临界区中,例如修改一个数值等。

由于自旋锁比较简单,pthread …

阅读全文…

pthread 学习笔记 (3)

读者-写者问题

一个缓冲区,有些进程只读取里面的内容,另外有的进程会修改里面的内容。为了保持数据的一致性,如果没有进程修改内容时,任意个读进程可以同时访问缓冲区,但是同一时间只能有一个写进程可以访问缓冲区,其它写进程和读进程都不能对缓冲区进行操作。

读者-写者问题和生产者-消费者问题不同的是,后者的每个线程都要修改缓冲区的内容,所以不得不使用互斥锁来保证数据一致性,而前者有些线程是只读的,多个只读线程同时访问并不会出现数据不一致的情况,所以在实现上不必为每个线程都加一个互斥锁,而是让多个读线程可以同时访问,只有写进程的访问是互斥的。

使用互斥锁实现

下面是利用 pthread_mutex 系列函数的实现。

#include <stdio.h>
#include <pthread.h>

struct pool {
   int nr_reader;
   unsigned long long value;
   pthread_mutex_t may_write, rd_count_mutex;
};

static void* writer(void* arg)
{
   struct pool* p = arg;

   while (1) {
      pthread_mutex_lock(&p->may_write);
      ++p->value;
      printf("writer: 

阅读全文…

pthread 学习笔记 (2)

互斥和同步

互斥(mutual exclusion,缩写mutex)是指一段区域在同一时间内只能有一个线程对其进行操作,否则会造成不一致的情况,这段区域叫做临界区。互斥只要求同一时间内只能有一个线程进行访问,但是线程之间的访问顺序可以是任意的;同步要求线程之间的访问有一定的顺序,并且一般都要求线程之间互斥访问(如果不修改临界区的值的话可以允许多个只读线程同时访问)。

生产者-消费者问题

同步和互斥的一个经典例子是生产者-消费者问题。假设一个缓冲区的大小为 N,如果缓冲区还没满,生产者每次可以往缓冲区里放入一个物品;如果缓冲区非空,消费者每次可以从缓冲区里取出一个物品。缓冲区是生产者和消费者共用的,同一时间内只能有一个线程可以对缓冲区进行修改,否则可能会出现错误。为了保证对缓冲区修改的原子性(即访问过程中不能被别的线程打断),可以对缓冲区加一个互斥锁(mutex lock)。当线程要访问缓冲区时需要先检查锁是否被其它线程占用,如果是的话就必须等待正在访问的线程释放;然后它占用互斥锁,防止别的线程在自己修改的过程中访问缓冲区;访问完毕后释放锁,让其它线程可以进行访问。

只有一个生产者和一个消费者

#include <stdio.h>
#include <pthread.h>

struct pool {
   pthread_mutex_t mutex;
#define MAX_NUM 5
   int num;
};

/* mutex should be held by the caller when one of the following four inline functions is 

阅读全文…

pthread 学习笔记 (1)

pthread 是 POSIX Thread 的缩写,是一套标准线程库,大部分的 *nix 系统都实现了它,在 windows 上也有相应的实现。这里的实验环境为 debian 6.0。

并行和并发(参考资料 [1])

并行的英文是 parallelism,并发的英文是 concurrency,两者表达的意思并不一样:并行是指多条指令 同时 执行(这里的“同时”指时间上的同时),而并发是指多条指令可能以任意顺序执行(也有可能是并行执行)。

第一个 pthread 程序

#include <stdio.h>
#include <pthread.h>

static void* print_tid(void* arg)
{
   printf("thread id: %d\n", *((int*)arg));

   return arg;
}

#define THREAD_NR 10


阅读全文…