抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

低配卖票很多问题 - 进程资源的抢占

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
/*************************************************************************
> File Name: selltickets.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 14时28分01秒
************************************************************************/

/*
* 使用多线程实现卖票案例
* 有3个窗口,一共是100张票
*
*/

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 全局变量,所有的线程都共享这一份资源 - 结果:不通的进程会卖同一张票
int tickets = 100;

void *sellticket(void *arg) {
// 卖票
// int tickets = 100; - 每个线程都会卖100张!
while(tickets > 0) {
usleep(6000);
printf("%ld 正在卖第 %d 张门票\n", pthread_self(), tickets--);
}
return NULL;
}

int main() {

// 创建3个子线程
pthread_t tid1, tid2, tid3;
pthread_create(&tid1, NULL, sellticket, NULL);
pthread_create(&tid2, NULL, sellticket, NULL);
pthread_create(&tid3, NULL, sellticket, NULL);


// 回收子线程资源,阻塞 --- 可以设置线程分离
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);

// 设置线程分离
/*
pthread_detach(tid1);
pthread_detach(tid2);
pthread_detach(tid3);
*/

// 退出主线程
pthread_exit(NULL);

return 0;
}

线程同步

  • 线程的主要优势在于,能够通过全局变量来共享信息。不过,这种便捷的共享是有代价的:必须确保多个线程不会同时修改同一变量,或者某一线程不会读取正在由其他线程 修改的变量。

  • 临界区是指访问某一共享资源的代码片段,并且这段代码的执行应为原子操作,也就是 同时访问同一共享资源的其他线程不应终端该片段的执行。

  • 线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进 行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作,而其他线程则处 于等待状态。

互斥锁(互斥量)

  • 为避免线程更新共享变量时出现问题,可以使用互斥量(mutex 是 mutual exclusion 的缩写)来确保同时仅有一个线程可以访问某项共享资源。可以使用互斥量来保证对任意共 享资源的原子访问。

  • 互斥量有两种状态:已锁定(locked)和未锁定(unlocked)。任何时候,至多只有一个线程可以锁定该互斥量。试图对已经锁定的某一互斥量再次加锁,将可能阻塞线程或者报 错失败,具体取决于加锁时使用的方法。

  • 一旦线程锁定互斥量,随即成为该互斥量的所有者,只有所有者才能给互斥量解锁。一般情 况下,对每一共享资源(可能由多个相关变量组成)会使用不同的互斥量,每一线程在访问 同一资源时将采用如下协议:

    • 针对共享资源锁定互斥量
    • 访问共享资源
    • 对互斥量解锁

如果多个线程试图执行这一块代码(一个临界区),事实上只有一个线程能够持有该互斥量(其他线程将遭到阻塞),即同时只有一个线程能够进入这段代码区域,如下图所示:

image-20220531163332190

互斥量(互斥锁)相关操作函数及介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
互斥量的类型 pthread_mutex_t
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
- 功能: 初始化互斥量
- 参数:
- mutex: 需要初始话的互斥量变量
- attr: 互斥量相关的属性NULL
- restrict: c语言的修饰符,被修饰的指针,不能由另外的一个指针进行 操作
pthread_mutex_t *restrict = mutex = xxx;
pthread_mutex_t *mutex1 = mutex; // 不允许
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);
- 释放锁(解锁)
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
97
98
99
/*************************************************************************
> File Name: mutex.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 16时36分54秒
************************************************************************/

/*
互斥量的类型 pthread_mutex_t
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
- 功能: 初始化互斥量
- 参数:
- mutex: 需要初始话的互斥量变量
- attr: 互斥量相关的属性NULL
- restrict: c语言的修饰符,被修饰的指针,不能由另外的一个指针进行 操作
pthread_mutex_t *restrict = mutex = xxx;
pthread_mutex_t *mutex1 = mutex; // 不允许
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);
- 释放锁(解锁)

*/

/*************************************************************************
> File Name: selltickets.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 14时28分01秒
************************************************************************/

/*
* 使用多线程实现卖票案例
* 有3个窗口,一共是100张票
*
*/

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 创建一个互斥量
pthread_mutex_t mutex;

// 全局变量,所有的线程都共享这一份资源 - (没加互斥锁的情况)结果:不通的 进程会卖同一张票
int tickets = 1000;

void *sellticket(void *arg) {

// 卖票
// int tickets = 100; - 每个线程都会卖100张!
while(1) {
// 加锁
pthread_mutex_lock(&mutex);
if(tickets > 0) {
usleep(6000);
printf("%ld 正在卖第 %d 张门票\n", pthread_self(), tickets--);
} else {
// 解锁
pthread_mutex_unlock(&mutex);
break;
}
// 解锁
pthread_mutex_unlock(&mutex);
}

return NULL;
}

int main() {

// 初始化互斥量
pthread_mutex_init(&mutex, NULL);

// 创建3个子线程
pthread_t tid1, tid2, tid3;
pthread_create(&tid1, NULL, sellticket, NULL);
pthread_create(&tid2, NULL, sellticket, NULL);
pthread_create(&tid3, NULL, sellticket, NULL);


// 回收子线程资源,阻塞 --- 可以设置线程分离
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);


// 退出主线程
pthread_exit(NULL);

// 释放互斥量资源
pthread_mutex_destroy(&mutex);

return 0;
}

死锁

  • 有时,一个线程需要同时访问两个或更多不同的共享资源,而每个资源又都由不同的互斥量管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁。

  • 两个或两个以上的进程在执行过程中,因争夺共享资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

  • 死锁的几种场景:

    • 忘记释放锁 // pthread_mutex_trylock() 尝试加锁判断
    • 重复加锁
    • 多线程多锁,抢占锁资源

image-20220531183939044

image-20220531185455335

image-20220531185445783

忘记加锁 - 可替换上述函数代码 尝试运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void *sellticket(void *arg) {

// 卖票
// int tickets = 100; - 每个线程都会卖100张!
while(1) {
// 加锁
pthread_mutex_lock(&mutex);
if(tickets > 0) {
usleep(6000);
printf("%ld 正在卖第 %d 张门票\n", pthread_self(), tickets--);
} else {
// 解锁
pthread_mutex_unlock(&mutex);
break;
}
// 解锁
// pthread_mutex_unlock(&mutex);
}

return NULL;
}

重复加锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void *sellticket(void *arg) {

// 卖票
// int tickets = 100; - 每个线程都会卖100张!
while(1) {
// 加锁
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);
if(tickets > 0) {
usleep(6000);
printf("%ld 正在卖第 %d 张门票\n", pthread_self(), tickets--);
} else {
// 解锁
pthread_mutex_unlock(&mutex);
break;
}
// 解锁
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock(&mutex);
}

return NULL;
}

多线程多锁,抢占锁资源 - C

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
/*************************************************************************
> File Name: deadlock1.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 19时09分34秒
************************************************************************/

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 创建2个互斥量
pthread_mutex_t mutex1, mutex2;

void *workA(void *arg) {

pthread_mutex_lock(&mutex1);
sleep(1);
pthread_mutex_lock(&mutex1);

printf("workA\n");

pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);

return NULL;
}

void *workB(void *arg) {
pthread_mutex_lock(&mutex2);
sleep(1);
pthread_mutex_lock(&mutex1);

printf("workB\n");

pthread_mutex_unlock(&mutex1);
pthread_mutex_unlock(&mutex2);

return NULL;
}

int main() {

// 初始化互斥量
pthread_mutex_init(&mutex1, NULL);
pthread_mutex_init(&mutex2, NULL);

// 创建2个子线程
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, workA, NULL);
pthread_create(&tid2, NULL, workB, NULL);

// 回收子线程资源
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

// 释放互斥量资源
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);

return 0;
}

读写锁

  • 当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想 读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读 访问共享资源了,但是实际上多个线程同时读访问共享资源并不会导致问题。

  • 在对数据的读写操作中,更多的是读操作,写操作较少,例如对数据库数据的读写应用。为了满足当前能够允许多个读出,但只允许一个写入的需求,线程提供了读写锁来实现。

  • 读写锁的特点:

    • 如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作。
    • 如果有其它线程写数据,则其它线程都不允许读、写操作。
    • 写是独占的,写的优先级高。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
读写锁的类型 pthread_rwlock_t
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
- 功能: 初始化读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
- 功能: 销毁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- 功能: 加读锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- 功能: 尝试加读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- 功能: 写锁
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
- 功能: 尝试加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- 功能: 关闭写

读写锁(案例) - C

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*************************************************************************
> File Name: rwlock.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年06月01日 星期三 10时27分52秒
************************************************************************/

/*
读写锁的类型 pthread_rwlock_t
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
- 功能: 初始化读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
- 功能: 销毁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- 功能: 加读锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- 功能: 尝试加读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- 功能: 写锁
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
- 功能: 尝试加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- 功能: 关闭写
*/

/*
案例:
创建8个线程操作同一个变量
3个线程不定时的写这个全局变量,5个线程不定时的读这个全局变量

*/


#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

// 创建一个共享数据
int num = 1;

// 创建一一个互斥量
pthread_mutex_t mutex;

// 创建一个读写锁
pthread_rwlock_t rwlock;

void *readNum(void *arg) {

while(1) {
// pthread_mutex_lock(&mutex);
pthread_rwlock_rdlock(&rwlock);
printf("==read, tid : %ld, num : %d\n", pthread_self(), num);
pthread_rwlock_unlock(&rwlock);
//pthread_mutex_unlock(&mutex);
usleep(100);
}
return NULL;
}

void *writeNum(void *arg) {

while(1) {
// pthread_mutex_lock(&mutex);
pthread_rwlock_wrlock(&rwlock);
num++;
printf("++write, tid : %ld, num : %d\n", pthread_self(), num);
pthread_rwlock_unlock(&rwlock);
//pthread_mutex_unlock(&mutex);
usleep(100);

}

return NULL;
}

int main() {

// 初始化互斥量
// pthread_mutex_init(&mutex, NULL);

// 初始化读写锁
pthread_rwlock_init(&rwlock, NULL);

// 创建3个写线程,5个度
pthread_t wtids[3], rtids[5];
for(int i = 0; i < 3; i++) {
pthread_create(&wtids[i], NULL, writeNum, NULL);
// 设置线程分离
pthread_detach(wtids[i]);
}

for(int i = 0; i < 5; i++) {
pthread_create(&rtids[i], NULL, readNum, NULL);
// 设置线程分离
// pthread_detach(rtids[i]);
}

/*
for(int i = 0; i < 3; i++) {
// 设置线程分离
pthread_detach(wtids[i]);
}
for(int i = 0; i < 5; i++) {
// 设置线程分离
pthread_detach(rtids[i]);
}
*/

// 退出父进程
pthread_exit(NULL);

// pthread_mutex_destroy(&mutex);
pthread_rwlock_destroy(&rwlock);

return 0;
}

生产者消费者模型

image-20220601135409287

image-20220601142226666

image-20220601142230699

条件变量

条件变量函数

1
2
3
4
5
6
7
8
9
10
11
12
13
条件变量的类型 pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
- 功能: 初始化
int pthread_cond_destroy(pthread_cond_t *cond);
- 功能: 释放
int pthread_cond_wait(pthread_cond_t *restrict cond,thread_mutex_t *restrict mutex);
- 功能: 等待,阻塞函数调用了该函数线程会阻塞
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
- 功能: 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间结束
int pthread_cond_signal(pthread_cond_t *cond);
- 功能: 唤醒一个或者多个等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
- 功能: 唤醒所以的等待的线程
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*************************************************************************
> File Name: cond.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年06月01日 星期三 19时49分46秒
************************************************************************/

/*
条件变量的类型 pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
- 功能: 初始化
int pthread_cond_destroy(pthread_cond_t *cond);
- 功能: 释放
int pthread_cond_wait(pthread_cond_t *restrict cond,thread_mutex_t *restrict mutex);
- 功能: 等待,阻塞函数调用了该函数线程会阻塞
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
- 功能: 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间结 束
int pthread_cond_signal(pthread_cond_t *cond);
- 功能: 唤醒一个或者多个等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
- 功能: 唤醒所以的等待的线程

*/

/*
* 生产者消费者模型(粗略版本)
*/

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

typedef struct Node {
int num;
struct Node *next;
} Node;

// 头节点
struct Node *head = NULL;
// 互斥量
pthread_mutex_t mutex;
// 创建一个条件变量
pthread_cond_t cond;

void *producer(void *arg) {

// 不断的创建新的节点,添加到链表中
while(1) {

pthread_mutex_lock(&mutex);

Node *newNode = (Node *)malloc(sizeof(Node));
newNode->num = rand() % 1000;
newNode->next = head;
head = newNode;
printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());

// 只要生成了一个,就通知消费者消费
pthread_cond_signal(&cond);

pthread_mutex_unlock(&mutex);
usleep(100);
}

return NULL;
}

void *customer(void *arg) {

while(1) {

pthread_mutex_lock(&mutex);
if(head != NULL) {

// 保存头节点的指针
Node *temp = head;
head = head->next;
printf("del node, num : %d, tid : %ld\n", temp->num, pthread_self());
free(temp);
} else {
// 没有数据需要等待
// 当这个函数调用阻塞时候会对互斥锁进行解锁,当不阻塞的,继续向下执行,会重新加锁
pthread_cond_wait(&cond, &mutex);
}

pthread_mutex_unlock(&mutex);
usleep(100);
}

return NULL;
}

int main() {

// 初始化信号量
pthread_mutex_init(&mutex, NULL);
// 初始化条件变量
pthread_cond_init(&cond, NULL);

// 创建5个生成者线程和5个消费者线程
pthread_t ptids[5], ctids[5];
for(int i = 0; i < 5; i++) {
pthread_create(&ptids[i], NULL, producer, NULL);
pthread_create(&ctids[i], NULL, customer, NULL);

}

for(int i = 0; i < 5; i++) {
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}

while(1) {
sleep(10);
}

pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_exit(NULL);


return 0;
}

信号量

信号量函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
信号量的类型 sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 功能: 初始化信号量
- 参数:
- sem: 信号量的的地址
- pshared: 0用在线程间、非0用在进程间
- value: 信号量中的值
int sem_destroy(sem_t *sem);
- 功能: 释放资源
int sem_wait(sem_t *sem);
- 功能: 对信号量加锁,对这个信号量的值减1,如果值为0,就阻塞
int sem_trywait(sem_t *sem);
- 功能: 尝试
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- 功能: 等待多长的时间
int sem_post(sem_t *sem);
- 功能: 对信号量解锁,调用一次对信号的值加1
int sem_getvalue(sem_t *sem, int *sval);
- 功能: 获取
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*************************************************************************
> File Name: semaphore.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年06月02日 星期四 13时35分42秒
************************************************************************/

/*
信号量的类型 sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 功能: 初始化信号量
- 参数:
- sem: 信号量的的地址
- pshared: 0用在线程间、非0用在进程间
- value: 信号量中的值
int sem_destroy(sem_t *sem);
- 功能: 释放资源
int sem_wait(sem_t *sem);
- 功能: 对信号量加锁,对这个信号量的值减1,如果值为0,就阻塞
int sem_trywait(sem_t *sem);
- 功能: 尝试
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- 功能: 等待多长的时间
int sem_post(sem_t *sem);
- 功能: 对信号量解锁,调用一次对信号的值加1
int sem_getvalue(sem_t *sem, int *sval);
- 功能: 获取

// 生
sem_t pesm;
// 消
sem_t csem;
init(pesm, 0, 8);
init(csem, 0, 0);

// 生产
prodicer() {
sem_wait(&osem);
sem_post(&csem);
}

// 消费
customer() {
sem_wait(&csem);
sem_post(&pesm);

}

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

typedef struct Node {
int num;
struct Node *next;
} Node;

// 头节点
struct Node *head = NULL;
// 互斥量
pthread_mutex_t mutex;
// 信号量
sem_t psem;
sem_t csem;

void *producer(void *arg) {

// 不断的创建新的节点,添加到链表中
while(1) {

sem_wait(&psem);
pthread_mutex_lock(&mutex);

Node *newNode = (Node *)malloc(sizeof(Node));
newNode->num = rand() % 1000;
newNode->next = head;
head = newNode;
printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());

pthread_mutex_unlock(&mutex);
sem_post(&csem);
usleep(100);
}

return NULL;
}

void *customer(void *arg) {

while(1) {
sem_wait(&csem);
pthread_mutex_lock(&mutex);
if(head != NULL) {

// 保存头节点的指针
Node *temp = head;
head = head->next;
printf("del node, num : %d, tid : %ld\n", temp->num, pthread_self());
free(temp);
}
pthread_mutex_unlock(&mutex);
sem_post(&psem);
usleep(100);
}

return NULL;
}

int main() {

// 初始化信号量
pthread_mutex_init(&mutex, NULL);
// 信号量初始化
sem_init(&psem, 0, 8);
sem_init(&csem, 0, 0);

// 创建5个生成者线程和5个消费者线程
pthread_t ptids[5], ctids[5];
for(int i = 0; i < 5; i++) {
pthread_create(&ptids[i], NULL, producer, NULL);
pthread_create(&ctids[i], NULL, customer, NULL);

}

for(int i = 0; i < 5; i++) {
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}

while(1) {
sleep(10);
}

pthread_mutex_destroy(&mutex);
pthread_exit(NULL);

return 0;
}

评论