Thread线程同步

线程包含了表示进程内执行环境必需的信息,其中包含进程中标识线程的线程ID、一组寄存器、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。

进程原语和线程原语的比较:

进程原语 | 线程原语 |描述
fork |pthread_create |创建新的控制流
exit |pthread_exit |从现有的控制流退出
waitpid |pthread_join |从控制流中得到退出的状态
atexit |pthread_cleanup_push|注册在退出控制流时调用的函数
getpid |pthread_self |获取控制流的ID
abort |pthread_cancel |请求控制流的非正常退出

当多个控制进程共享相同的内存时,就需要线程同步机制,以保证它们在访问变量的存储内容时不会访问到无效的数值。线程同步机制:

1.互斥量,互斥量从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。

互斥量
1
2
3
4
5
6
7
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t  *mutex);

2.读写锁,当读操作比较频繁时,读写锁可以改善性能。

读写锁例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdlib.h>
#include <pthread.h>
struct job {
    struct job *j_next;
    struct job *j_prev;
    pthread_t    j_id;          /*告诉哪条线程在操作任务*/
    /*...更多的定义在后面*/
};

struct queue {
    struct job *q_head;
    struct job *q_tail;
    pthread_rwlock_t q_lock;
};

/*初始化队列*/
int queue_init(struct queue *qp)
{
    int err;

    qp->q_head = NULL;
    qp->q_tail =  NULL;
    err = pthread_rwlock_init(&qp->q_lock, NULL);
    if ( err != 0)
        return (err);
    /*...继续初始化*/
    return (0);
}

/*在队列的前面插入一个任务*/
void job_insert( struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_next = qp->q_head;
    jp->j_prev = NULL;
    if( qp->q_head != NULL)
        qp->q_head->j_prev = jp;
    else
        qp->q_tail = jp;     /*队列是空的*/
    qp->q_head = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}

/*在队列的尾部添加一个任务*/
void job_append(struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_next = NULL;
    jp->j_prev = qp->q_tail;
    if( qp->q_tail != NULL)
        qp->q_tail->j_next = jp;
    else
        qp->q_head = jp;   /*队列是空的*/
    qp->tail = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}

/*在队列中删除一个任务*/
void job_remove(struct queue *qp, struct job *jp)
{
    pthead_rwlock_wrlock(&qp->q_lock);
    if( jp == qp->q_head)
        {
            qp->q_head = jp->j_next;
            if( qp->tail == jp)
                qp->q_tail = NULL;
        }
    else if( jp == qp->q_tail)
        {
            qp->q_tail = jp->j_prev;
            if( qp->q_head == jp)
                qp->q_head = NULL;
        }
    else
        {
            jp->j_prev->j_next = jp->j_next;
            jp->j_next->j_prev = jp->j_prev;
        }
       pthread_rwlock_unlock(&qp->q_lock);
}

/*在队列中根据线程找到任务*/
struct job *job_find( struct queue *qp, pthread_t id)
{
    struct job *jp;

    if ( pthread_rwlock_rdlock(&qp->q_lock) != 0)
        return (NULL);

    for( jp = qp->q_head; jp != NULL; jp = jp->j_next)
        if( pthread_equal(jp->j_id, id))
            break;

    pthread_rwlock_unlock(&qp->q_lock);
    return (jp);
}

3.条件变量,条件变量与互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。

互斥量
1
2
3
4
5
6
7
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
                    pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

线程的基本的同步机制:互斥、读写锁及条件变量,了解如何使用它们保护共享资源。

Comments