同步与互斥这两个概念经常被混淆,所以在这里说一下它们的区别。
一、同步与互斥的区别
1. 同步
同步,又称直接制约关系,是指多个线程(或进程)为了合作完成任务,必须严格按照规定的 某种先后次序来运行。
例如,线程 T2 中的语句 y 要使用线程 T1 中的语句 x 的运行结果,所以只有当语句 x 执行完成之后语句 y 才可以执行。我们可以使用信号量进行同步:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15semaphore S=0; // 初始化信号量 T1() { ... x; // 语句x V(S); // 告诉线程T2,语句x已经完成 ... } T2() { ... P(S); // 检查语句x是否运行完成 y; // 检查无误,运行y语句 ... }
2. 互斥
互斥,又称间接制约关系,是指系统中的某些共享资源,一次只允许一个线程访问。当一个线程正在访问该临界资源时,其它线程必须等待。
例如,打印机就是一种临界资源,而访问打印机的代码片段称为临界区,故每次只允许一个线程进入临界区。—— 我们同样可以使用信号量解决互斥问题,只需把临界区置于 P(S) 和 V(S) 之间,即可实现两线程对临界资源的互斥访问。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17semaphore S=1; // 初始化信号量 T1() { ... P(S); 线程T1的临界区; // 访问临界资源 V(S); ... } T2() { ... P(S); 线程T2的临界区; // 访问临界资源 V(S); ... }
二、一个同步的例子
如下图,为了求出 1 到 n 的平均值,需要三个线程协调它们的工作次序来完成,这就是同步:

为了使多个线程按顺序正确执行,应设置若干个初始值为 0 的信号量:
复制代码
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#include<iostream> #include<pthread.h> #include"semaphore.hpp" using namespace std; int sem1, sem2; int n = 10; /*1...n的平均值*/ int sum = 0; double average = 0; void* t1(void* arg) { for(int i=1; i<=n; ++i) sum += i; sem_v(sem1); /*V操作,通知t2求和已完成*/ } void* t2(void* arg) { sem_p(sem1); /*P操作,等待t1完成*/ average = (double)sum/n; sem_v(sem2); /*V操作,通知main求平均已完成*/ } int main() { sem1 = creat_sem("/" , 0); /*创建信号量*/ sem2 = creat_sem("/home", 0); pthread_t id[2]; pthread_create(&id[0], NULL, t1, NULL); pthread_create(&id[1], NULL, t2, NULL); sem_p(sem2); /*P操作,等待t2完成*/ cout << "The sum is: " << sum << endl; cout << "The average is: " << average << endl; del_sem(sem1); /*删除信号量*/ del_sem(sem2); return 0; }
下面是信号量的相关函数,详见《信号量》。
复制代码
线程 t2 需要等待线程 t1 (求和)完成以后才能够执行;主线程 main 需要等待线程 t2 (求平均)完成以后才能够执行输出。编译运行结果如下:
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// semaphore.hpp #include<cstdio> #include<cstdlib> #include<sys/sem.h> // 联合体,用于semctl初始化 union semun { int val; /*for SETVAL*/ struct semid_ds *buf; unsigned short *array; }; // 初始化信号量 int init_sem(int sem_id, int value) { union semun tmp; tmp.val = value; if(semctl(sem_id, 0, SETVAL, tmp) == -1) { perror("Init Semaphore Error"); return -1; } return 0; } // P操作: // 若信号量值为1,获取资源并将信号量值-1 // 若信号量值为0,进程挂起等待 int sem_p(int sem_id) { struct sembuf sbuf; sbuf.sem_num = 0; /*序号*/ sbuf.sem_op = -1; /*P操作*/ sbuf.sem_flg = SEM_UNDO; if(semop(sem_id, &sbuf, 1) == -1) { perror("P operation Error"); return -1; } return 0; } // V操作: // 释放资源并将信号量值+1 // 如果有进程正在挂起等待,则唤醒它们 int sem_v(int sem_id) { struct sembuf sbuf; sbuf.sem_num = 0; /*序号*/ sbuf.sem_op = 1; /*V操作*/ sbuf.sem_flg = SEM_UNDO; if(semop(sem_id, &sbuf, 1) == -1) { perror("V operation Error"); return -1; } return 0; } // 删除信号量集 int del_sem(int sem_id) { union semun tmp; if(semctl(sem_id, 0, IPC_RMID, tmp) == -1) { perror("Delete Semaphore Error"); return -1; } return 0; } // 创建信号量,返回其ID int creat_sem(const char* path, int value) { int sem_id; /*信号量集ID*/ key_t key; /*获取key值*/ if((key = ftok(path, 'z')) < 0) { perror("ftok error"); exit(1); } /*创建信号量集,其中只有一个信号量*/ if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1) { perror("semget error"); exit(1); } init_sem(sem_id, value); return sem_id; }
复制代码
1
2
3
4$ g++ -lpthread -o synchronized synchronized.cpp $ ./synchronized The sum is: 55 The average is: 5.5
最后
以上就是昏睡月饼最近收集整理的关于Linux多线程编程--同步与互斥 一、同步与互斥的区别 二、一个同步的例子的全部内容,更多相关Linux多线程编程--同步与互斥内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复