线程包含了表示进程内执行环境必需的信息,其中包含进程中标识线程的线程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);
|
线程的基本的同步机制:互斥、读写锁及条件变量,了解如何使用它们保护共享资源。