2012年4月1日日曜日

[C 语言] 多线程中的锁定资源

1. 互斥量
本质上说就是一把锁, 提供对共享资源的保护访问

1-1. 初始化
静态分配的互斥量, 可以设置为 PTHREAD_MUTEX_INITIALIZER, 或调用 pthread_mutex_init
动态分配的互斥量, 在申请内存 (malloc) 之后, 通过 pthread_mutex_init 初始化, 并在释放内存 (free) 前调用 pthread_mutex_destroy

1-1-1. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restric attr);

1-1-2. int pthread_mutex_destroy(pthread_mutex_t *mutex);

返回值: 成功则返回0, 出错则返回错误编号

1-2. 互斥操作
对共享资源的访问, 要对互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁
在完成了对共享资源的访问后, 要对互斥量进行解锁

1-2-1. int pthread_mutex_lock(pthread_mutex_t *mutex);

1-2-2. int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞调用模式, 如果互斥量没被锁住, 将把互斥量加锁, 并获得对共享资源的访问权限
如果互斥量被锁住了, 将不会阻塞等待而直接返回 EBUSY, 表示共享资源处于忙状态

返回值: 成功则返回0, 出错则返回错误编号

1-3. 解锁函数

1-3-1. int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值: 成功则返回0, 出错则返回错误编号

1-4. 简单实例

/* gcc -o lock -lpthread lock.c */
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

static pthread_mutex_t testlock;
pthread_t test_thread;

void *test()
{
    int i;
    pthread_mutex_lock(&testlock);
    for(i = 0; i < 5; i++)
    {
        printf("[%d] thread running... \n", i + 1);
        sleep(2);
    }
    pthread_mutex_unlock(&testlock);
}

int main()
{
    pthread_mutex_init(&testlock, NULL);
    pthread_create(&test_thread, NULL, test, NULL);
    sleep(1);

    int locked;
    while(1)
    {
        locked = pthread_mutex_trylock(&testlock);
        if(locked)
        {
            printf("locked, I'm waiting...\n");
            sleep(1);
            continue;
        }
        else
            break;
    }

    printf("main lock \n");
    // pthread_mutex_lock(&testlock);
    printf("main doing some thing...\n");
    sleep(1);
    printf("main unlock \n");
    pthread_mutex_unlock(&testlock);

    printf("waiting for sub thread...\n");
    pthread_join(test_thread, NULL);
    pthread_mutex_destroy(&testlock);
    exit(0);
}

================================================================================
2. 条件变量

利用线程间共享的全局变量进行同步的一种机制
包括两个动作: 一个线程等待 "条件变量的条件成立" 而挂起, 另一个线程使 "条件成立" (给出条件成立信号)
为了防止竞争, 条件变量的使用总是和一个互斥锁结合在一起

2-1. 创建和注销

2-1-1. 静态创建
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2-1-2. 动态创建
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)

2-1-3. 注销
int pthread_cond_destroy(pthread_cond_t *cond)
只有在没有线程在该条件变量上等待的时候才能注销这个条件变量, 否则返回 EBUSY


2-2. 等待和激发

2-2-1. 无条件等待
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

2-2-2. 计时等待
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
如果在给定时刻前条件没有满足, 则返回 ETIMEOUT, 结束等待, 其中 abstime 是绝对时间形式, 0 表示格林尼治时间1970年1月1日0时0分0秒


2-2-3. 激发条件
pthread_cond_signal(pthread_cond_t *cond), 激活一个等待该条件的线程, 存在多个等待线程时按入队顺序激活其中一个
pthread_cond_broadcast(pthread_cond_t *cond), 激活所有等待线程, 两者如果没有等待的线程, 则什么也不做

2-3. 简单实例

/* gcc -o cond cond.c -lpthread */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t m;
pthread_cond_t c;

void *t1(void *arg)
{
    printf("thread1 : t1() start!\n");
    pthread_mutex_lock(&m);
    printf("thread1 : t1() waiting...\n");
    pthread_cond_wait(&c, &m); // 等待
    printf("thread1 : t1() ok!\n");
    pthread_mutex_unlock(&m);
    printf("thread1 : t1() end!\n");
}

void *t2(void *arg)
{
    printf("thread2 : t2() start!\n");
    sleep(5);
    printf("thread2 : t2() wake up thread1!\n");
    pthread_cond_signal(&c); // 唤醒 thread1
    printf("thread2 : t2() end!\n");
}

int main(int argc, char **argv)
{
    pthread_t a, b;
    pthread_mutex_init(&m, NULL);

    pthread_create(&a, NULL, (void *)t1, NULL);
    pthread_create(&b, NULL, (void *)t2, NULL);

    sleep(10);
    exit(0);
}

0 件のコメント:

コメントを投稿