读写锁

250 篇文章 0 订阅

在许多情况下,数据的读取比修改或写入更频繁。

在这些情况下,可允许线程在保留锁的同时进行读取,且在修改数据时只允许一个线程保留锁。多读单写锁(或读写锁)可做到这一点。在读取或写入时获取读写锁,然后将其释放。获取读写锁的线程一定是释放它的线程。

读写属性对象

pthread_rwlockattr_init 子例程初始化读写锁属性对象 (attr)。所有属性的缺省值由该实现来定义。如果 pthread_rwlockattr_init 子例程指定了已经初始化的读写锁属性对象,那么可能发生无法预料的结果。

以下示例说明了如何以  attr 对象调用  pthread_rwlockattr_init 子例程:
pthread_rwlockattr_t    attr;
和:
pthread_rwlockattr_init(&attr);

在读写锁属性对象被用于初始化一个或多个后,任何影响该属性对象的函数(包括析构函数)不会影响任何以前已初始化的读写锁。

pthread_rwlockattr_destroy 子例程删除读写锁属性对象。如果该对象在其被别的 pthread_rwlockattr_init 子例程的调用重新初始化前被使用,那么可能发生无法预料的结果。实现可能导致 pthread_rwlockattr_destroy 子例程将由 attr 对象所引用的对象设为无效值。

创建和破坏读写锁

pthread_rwlock_init 子例程用 attr 对象所引用的属性来初始化 rwlock 对象所引用的读写锁。如果 attr 对象为 NULL,那么使用缺省的读写锁属性;其效果与传递缺省读写锁属性对象的地址相同。初始化成功后,读写锁的状态变为已初始化和已解锁。初始化后,该锁可以被使用任意次,而无需重新初始化。如果调用 pthread_rwlock_init 子例程时指定了已初始化的读写锁,或者没有首先初始化就使用了读写锁,那么可能发生无法预料的结果。

如果 pthread_rwlock_init 子例程失败,那么 rwlock 对象不会被初始化且其内容是不确定的。

pthread_rwlock_destroy 子例程删除  rwlock 对象引用的读写锁对象并释放该锁使用的所有资源。在以下任一情况中都可能发生无法预料的结果:
  • 如果该锁在其被另一个对 pthread_rwlock_init 子例程的调用重新初始化前被使用。
  • 实现可能导致 pthread_rwlock_destroy 子例程将由 rwlock 对象所引用的对象设为无效值。如果任何线程保留 rwlock 对象时 pthread_rwlock_destroy 被调用,那么可能发生无法预料的结果。
  • 尝试删除未初始化的读写锁将导致无法预料的结果。已删除的读写锁对象可使用 pthread_rwlock_init 子例程来重新初始化。如果在其被删除后又引用了读写锁对象,那么可能发生无法预料的结果。
在缺省读写锁属性适合的情况下,使用  PTHREAD_RWLOCK_INITIALIZER 宏初始化静态分配的读写锁。例如:
pthread_rwlock_t        rwlock1 = PTHREAD_RWLOCK_INITIALIZER;
除了不执行错误检查外,其效果与使用将  attr 参数指定为 NULL 的  pthread_rwlock_init 子例程调用的效果相似。例如:
pthread_rwlock_init(&rwlock2, NULL);
以下示例说明了如何使用 attr 参数已初始化的  pthread_rwlock_init 子例程。要获取如何初始化  attr 参数的示例,请参阅 读写属性对象
pthread_rwlock_init(&rwlock, &attr);

锁定读写锁对象进行读取

pthread_rwlock_rdlock 子例程将读取锁应用到由 rwlock 对象所引用的读写锁。如果写程序没有保留读取锁,且没有被该锁阻塞的写程序,那么调用线程获取该读取锁。未指定在写程序没有保留该锁且有写程序在等待该锁时调用线程是否要获取该锁。如果写程序保留了该锁,调用线程将不会获取该读取锁。如果没有获取读取锁,调用线程就不从 pthread_rwlock_rdlock 调用返回,直到它获取该锁。如果调用线程在进行调用时保留了 rwlock 对象的写入锁,那么结果是不确定的。

线程可控制 rwlock 对象的多个并发读取锁(即成功调用 pthread_rwlock_rdlock 子例程 n 次)。如果是这样的话,该线程必须执行匹配的解锁(即它必须调用 pthread_rwlock_unlock 子例程 n 次)。

pthread_rwlock_tryrdlock 子例程对读取锁的应用与 pthread_rwlock_rdlock 子例程大致相似,除了一种情况,即在有任何线程保留 rwlock 对象的写入锁或有写程序在 rwlock 对象上阻塞时该子例程会失败。如果有未初始化的读写锁而调用这些函数中的任一,其结果会是无法预料的。

如果信号传递给一个正在等待读写锁进行读取的线程,在从信号处理程序返回时,该线程将继续等待读写锁以进行读取,就好像没有中断过一样。

锁定读写锁对象进行写入

pthread_rwlock_wrlock 子例程将写入锁应用到 rwlock 对象引用的读写锁。如果没有其他线程(读程序或写程序)保留 rwlock 对象的读写锁,调用线程将获取写入锁。否则,该线程不会从 pthread_rwlock_wrlock 调用返回,直到它可以获取该锁。如果调用线程在进行调用时保留该读写锁(无论是读取锁还是写入锁),那么结果是不确定的。

pthread_rwlock_trywrlock 子例程对写入锁的应用与 pthread_rwlock_wrlock 子例程大致相似,除了一种情况,即如果任何线程当前保留了 rwlock 以进行读取或写入时该函数会失败。如果有未初始化的读写锁而调用这些函数中的任一,其结果会是无法预料的。

如果信号传递给一个正在等待读写锁进行写入的线程,在从信号处理程序返回时,该线程继续等待读写锁以进行写入,就好像没有中断过一样。

样本读写锁程序

以下样本程序演示了如何使用锁定子例程。要运行这些程序,需要 check.h 文件和 makefile

check.h 文件:
#include stdio.h
#include stdio.h
#include stdio.h
#include stdio.h

/* Simple function to check the return code and exit the program
   if the function call failed
   */
static void compResults(char *string, int rc) {
  if (rc) {
    printf("Error on : %s, rc=%d",
           string, rc);
          exit(EXIT_FAILURE);
  }
                       return;
}
Make 文件:
CC_R = xlc_r

TARGETS = test01 test02 test03

OBJS = test01.o test02.o test03.o

SRCS = $(OBJS:.o=.c)

$(TARGETS): $(OBJS)
    $(CC_R) -o $@ $@.o

clean:
    rm $(OBJS) $(TARGETS)

run:
        test01
        test02
    test03

单线程示例

以下示例以单线程来使用 pthread_rwlock_tryrdlock 子例程。要获取以多线程来使用 pthread_rwlock_tryrdlock 子例程的示例,请参阅多线程示例

Example: test01.c

#define _MULTI_THREADED
#include pthread.h
#include stdio.h
#include "check.h"

pthread_rwlock_t       rwlock = PTHREAD_RWLOCK_INITIALIZER;

void *rdlockThread(void *arg)
{
    int             rc;
  int             count=0;

  printf("Entered thread, getting read lock with mp wait\n");
    Retry:
  rc = pthread_rwlock_tryrdlock(&rwlock);
  if (rc == EBUSY) {
    if (count >= 10) {
      printf("Retried too many times, failure!\n");

            exit(EXIT_FAILURE);
    }
        ++count;
    printf("Could not get lock, do other work, then RETRY...\n");
                  sleep(1);
    goto Retry;
  }
  compResults("pthread_rwlock_tryrdlock() 1\n", rc);

    sleep(2);

  printf("unlock the read lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("Secondary thread complete\n");
  return NULL;
}

int main(int argc, char **argv)
{
  int                   rc=0;
    pthread_t             thread;

  printf("Enter test case - %s\n", argv[0]);

  printf("Main, get the write lock\n");
  rc = pthread_rwlock_wrlock(&rwlock);
  compResults("pthread_rwlock_wrlock()\n", rc);

  printf("Main, create the try read lock thread\n");
  rc = pthread_create(&thread, NULL, rdlockThread, NULL);
  compResults("pthread_create\n", rc);

  printf("Main, wait a bit holding the write lock\n");
    sleep(5);

  printf("Main, Now unlock the write lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("Main, wait for the thread to end\n");
  rc = pthread_join(thread, NULL);
  compResults("pthread_join\n", rc);

  rc = pthread_rwlock_destroy(&rwlock);
  compResults("pthread_rwlock_destroy()\n", rc);
  printf("Main completed\n");
    return 0;
}

此样本程序的输出与以下内容相似:

Enter test case - ./test01
Main, get the write lock
Main, create the try read lock thread
Main, wait a bit holding the write lock

Entered thread, getting read lock with mp wait
Could not get lock, do other work, then RETRY...
Could not get lock, do other work, then RETRY...
Could not get lock, do other work, then RETRY...
Could not get lock, do other work, then RETRY...
Could not get lock, do other work, then RETRY...
Main, Now unlock the write lock
Main, wait for the thread to end
unlock the read lock
Secondary thread complete
Main completed

多线程示例

以下示例以多线程来使用 pthread_rwlock_tryrdlock 子例程。要获取以单线程来使用 pthread_rwlock_tryrdlock 子例程的示例,请参阅单线程示例

Example: test02.c

#define _MULTI_THREADED
#include pthread.h
#include stdio.h
#include "check.h"

pthread_rwlock_t       rwlock = PTHREAD_RWLOCK_INITIALIZER;

void *wrlockThread(void *arg)
{
    int             rc;
  int             count=0;

  printf("%.8x: Entered thread, getting write lock\n",
                    pthread_self());
    Retry:
  rc = pthread_rwlock_trywrlock(&rwlock);
  if (rc == EBUSY) {
    if (count >= 10) {
      printf("%.8x: Retried too many times, failure!\n",
                        pthread_self());
            exit(EXIT_FAILURE);
    }

        ++count;
    printf("%.8x: Go off an do other work, then RETRY...\n",
                      pthread_self());
                  sleep(1);
    goto Retry;
  }
  compResults("pthread_rwlock_trywrlock() 1\n", rc);
  printf("%.8x: Got the write lock\n", pthread_self());

    sleep(2);

  printf("%.8x: Unlock the write lock\n",
                    pthread_self());
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("%.8x: Secondary thread complete\n",
                    pthread_self());
  return NULL;
}

int main(int argc, char **argv)
{
  int                   rc=0;
  pthread_t             thread, thread2;

  printf("Enter test case - %s\n", argv[0]);

  printf("Main, get the write lock\n");
  rc = pthread_rwlock_wrlock(&rwlock);
  compResults("pthread_rwlock_wrlock()\n", rc);

  printf("Main, create the timed write lock threads\n");
  rc = pthread_create(&thread, NULL, wrlockThread, NULL);
  compResults("pthread_create\n", rc);

  rc = pthread_create(&thread2, NULL, wrlockThread, NULL);
  compResults("pthread_create\n", rc);

  printf("Main, wait a bit holding this write lock\n");
                sleep(1);

  printf("Main, Now unlock the write lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("Main, wait for the threads to end\n");
  rc = pthread_join(thread, NULL);
  compResults("pthread_join\n", rc);

  rc = pthread_join(thread2, NULL);
  compResults("pthread_join\n", rc);

  rc = pthread_rwlock_destroy(&rwlock);
  compResults("pthread_rwlock_destroy()\n", rc);
  printf("Main completed\n");
    return 0;
}

此样本程序的输出与以下内容相似:

Enter test case - ./test02
Main, get the write lock
Main, create the timed write lock threads
Main, wait a bit holding this write lock
00000102: Entered thread, getting write lock 
00000102: Go off an do other work, then RETRY...
00000203: Entered thread, getting write lock
00000203: Go off an do other work, then RETRY...
Main, Now unlock the write lock
Main, wait for the threads to end
00000102: Got the write lock
00000203: Go off an do other work, then RETRY...
00000203: Go off an do other work, then RETRY...
00000102: Unlock the write lock
00000102: Secondary thread complete
00000203: Got the write lock
00000203: Unlock the write lock
00000203: Secondary thread complete
Main completed

读写读取锁示例

以下示例使用 pthread_rwlock_rdlock 子例程来实现读写读取锁:

Example: test03.c

#define _MULTI_THREADED
#include pthread.h
#include stdio.h
#include "check.h"

pthread_rwlock_t       rwlock;

void *rdlockThread(void *arg)
{
  int rc;

  printf("Entered thread, getting read lock\n");
  rc = pthread_rwlock_rdlock(&rwlock);
  compResults("pthread_rwlock_rdlock()\n", rc);
  printf("got the rwlock read lock\n");

  sleep(5);

  printf("unlock the read lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);
  printf("Secondary thread unlocked\n");
  return NULL;
}

void *wrlockThread(void *arg)
{
  int rc;

  printf("Entered thread, getting write lock\n");
  rc = pthread_rwlock_wrlock(&rwlock);
  compResults("pthread_rwlock_wrlock()\n", rc);

  printf("Got the rwlock write lock, now unlock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);
  printf("Secondary thread unlocked\n");
  return NULL;
}



int main(int argc, char **argv)
{
  int                   rc=0;
  pthread_t             thread, thread1;

  printf("Enter test case - %s\n", argv[0]);

  printf("Main, initialize the read write lock\n");
  rc = pthread_rwlock_init(&rwlock, NULL);
  compResults("pthread_rwlock_init()\n", rc);

  printf("Main, grab a read lock\n");
  rc = pthread_rwlock_rdlock(&rwlock);
  compResults("pthread_rwlock_rdlock()\n",rc);


  printf("Main, grab the same read lock again\n");
  rc = pthread_rwlock_rdlock(&rwlock);
  compResults("pthread_rwlock_rdlock() second\n", rc);

  printf("Main, create the read lock thread\n");
  rc = pthread_create(&thread, NULL, rdlockThread, NULL);
  compResults("pthread_create\n", rc);

  printf("Main - unlock the first read lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("Main, create the write lock thread\n");
  rc = pthread_create(&thread1, NULL, wrlockThread, NULL);
  compResults("pthread_create\n", rc);

  sleep(5);
  printf("Main - unlock the second read lock\n");
  rc = pthread_rwlock_unlock(&rwlock);
  compResults("pthread_rwlock_unlock()\n", rc);

  printf("Main, wait for the threads\n");
  rc = pthread_join(thread, NULL);
  compResults("pthread_join\n", rc);

  rc = pthread_join(thread1, NULL);
  compResults("pthread_join\n", rc);

  rc = pthread_rwlock_destroy(&rwlock);
  compResults("pthread_rwlock_destroy()\n", rc);

  printf("Main completed\n");
  return 0;
}

此样本程序的输出与以下内容相似:

$ ./test03
Enter test case - ./test03
Main, initialize the read write lock
Main, grab a read lock
Main, grab the same read lock again
Main, create the read lock thread
Main - unlock the first read lock
Main, create the write lock thread
Entered thread, getting read lock
got the rwlock read lock
Entered thread, getting write lock
Main - unlock the second read lock
Main, wait for the threads
unlock the read lock
Secondary thread unlocked
Got the rwlock write lock, now unlock
Secondary thread unlocked
Main completed
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值