lock

os是多任务操作系统,同一个进程下面是可以有多个线程(进程)同时运行的,线程实际也是一个进程,只是对父进程的一个copy,与父进程共享地址空间进程,所以对同一进程共享的资源需要进行同步,同步的方法包括mutex semaphore spinlock 条件变量

很多东西如果只停留在概念层面远远是不够的,我们还是要不断的思考下面的实现机制和原理,下面说下同步的东西。

semaphore

1
2
3
4
5
6
7
8
9
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
};
typedef struct {
volatile int counter;
} atomic_t;

锁的实现原理其实就是通过上面一个结构实现的,通过对counter这个值的变化来实现锁的拥有和释放。上面的结构体的字段的意思言简意赅。

信号量是可以用在进程间和同一进程的线程间的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int sem_init(sem_t *sem, int pshared, unsigned int value);
// 初始化一个信号量
// sem 就是上面的结构
// pshared 0 代表线程间通信 非0 不同进程间
// value 初始化counter的值
int sem_wait(sem_t *sem);
// 获取锁(得不到会放到等待队列)
// > 0 获得锁,然后计数减少1
int sem_trywait(sem_t *sem);
// 尝试获取锁(得不到会立即返回不会放到等待队列)
// 获取不到的时候会返回EAGAIN错误码
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
// 过了指定时间尝试获取锁,得不到就返回ETIMEDOUT错误码
int sem_post(sem_t *sem);
// 释放锁,然后计数增加1

example:

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
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
sem_t sem;
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void
handler(int sig)
{
write(STDOUT_FILENO, "sem_post() from handler\n", 24);
if (sem_post(&sem) == -1) {
write(STDERR_FILENO, "sem_post() failed\n", 18);
_exit(EXIT_FAILURE);
}
}
int
main(int argc, char *argv[])
{
struct sigaction sa;
struct timespec ts;
int s;
if (argc != 3) {
fprintf(stderr, "Usage: %s <alarm-secs> <wait-secs>\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (sem_init(&sem, 0, 0) == -1)
handle_error("sem_init");
/* Establish SIGALRM handler; set alarm timer using argv[1] */
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGALRM, &sa, NULL) == -1)
handle_error("sigaction");
alarm(atoi(argv[1]));
/* Calculate relative interval as current time plus
number of seconds given argv[2] */
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
handle_error("clock_gettime");
ts.tv_sec += atoi(argv[2]);
printf("main() about to call sem_timedwait()\n");
while ((s = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR)
continue; /* Restart if interrupted by handler */
/* Check what happened */
if (s == -1) {
if (errno == ETIMEDOUT)
printf("sem_timedwait() timed out\n");
else
perror("sem_timedwait");
} else
printf("sem_timedwait() succeeded\n");
exit((s == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
}

1
2
3
4
5
6
7
8
$ ./a.out 2 3
About to call sem_timedwait()
sem_post() from handler
sem_getvalue() from handler; value = 1
sem_timedwait() succeeded
$ ./a.out 2 1
About to call sem_timedwait()
sem_timedwait() timed out

mutex

互斥量实际是counter初始值为1的信号量,只是我们通常用于线程间来通信。互斥锁可以分为递归和非递归锁,同样可以为这mutex设置多种类型,下面有说明。

1
2
3
4
5
6
7
typedef struct semaphore mutex_t;
#define mutex_init(lock, type, name) sema_init(lock, 1)
#define mutex_destroy(lock) sema_init(lock, -99)
#define mutex_lock(lock, num) down(lock)
#define mutex_trylock(lock) (down_trylock(lock) ? 0 : 1)
#define mutex_unlock(lock) up(lock)
1
2
3
4
5
6
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

spinlock