[学习]多线程锁

信号量使用

在多线程条件下,完成对🥧的计算。实验提供有单线程版本,要求进行修改,并在代码空白处实现多线程计算。学习使用信号量,防止在多线程计算最终结果时出错。

一、原理

利用级数的思想,将计算过程分为多个线程,每个线程计算🥧的一部分,最后将结果相加。 求🥧的问题是一个累加问题,不同线程计算自己的项数和,然后输出汇总到一个解上,这里限定为一块共享内存。 因为不同的线程运行速度有快有慢,如果碰上两个线程对同一个共享内存进行加法操作,就会出现计算错误,为此需要引入信号量sem_t。

sem_t的基本使用方法如下。

1
2
3
4
5
6
7
#include <semaphore>	# 引入这个库

sem_t sem # 新建一个信号量
sem_init(&sem ,0 ,1) # 在main中调用将信号量初始化为1
sem_wait(&sem) # 在进入临界区之前,等待锁释放
sem_post(&sem) # 临界区代码运行完毕后释放掉信号量
sem_destory(&sem) # 在主线程运行结束后,调用释放掉信号量

二、源代码

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
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>

#define GET_TIME(now) \
{ \
struct timeval t; \
gettimeofday(&t, NULL); \
now = t.tv_sec + t.tv_usec / 1000000.0; \
}

const int MAX_THREADS = 1024;

long thread_count;
long long n;
double sum;

sem_t sem;

void *Thread_sum(void *rank);

/* Only executed by main thread */
void Get_args(int argc, char *argv[]);
void Usage(char *prog_name);
double Serial_pi(long long n);

int main(int argc, char *argv[])
{
long thread; /* Use long in case of a 64-bit system */
pthread_t *thread_handles;
double start, finish, elapsed;

/* please choose terms 'n', and the threads 'thread_count' here. */
n = 10000000000; // 控制计算项数
thread_count = 4; // 线程数

/* You can also get number of threads from command line */
//Get_args(argc, argv);

thread_handles = (pthread_t *)malloc(thread_count * sizeof(pthread_t));
sem_init(&sem, 0, 1);
sum = 0.0;

GET_TIME(start);
for (thread = 0; thread < thread_count; thread++)
pthread_create(&thread_handles[thread], NULL,
Thread_sum, (void *)thread);

for (thread = 0; thread < thread_count; thread++)
pthread_join(thread_handles[thread], NULL);
GET_TIME(finish);
elapsed = finish - start;

sum = 4.0 * sum;
printf("With n = %lld terms,\n", n);
printf(" Our estimate of pi = %.15f\n", sum);
printf("The elapsed time is %e seconds\n", elapsed);
GET_TIME(start);
sum = Serial_pi(n);
GET_TIME(finish);
elapsed = finish - start;
printf(" Single thread est = %.15f\n", sum);
printf("The elapsed time is %e seconds\n", elapsed);
printf(" pi = %.15f\n", 4.0 * atan(1.0));

sem_destroy(&sem);
free(thread_handles);
return 0;
} /* main */

/*------------------------------------------------------------------*/
void *Thread_sum(void *rank)
{
long my_rank = (long long)rank;
double my_sum = 0.0;

/*******************************************************************/
double factor = 1;
long long max_size = 0;
if (my_rank == 3) // 平均分配计算量,最后一个线程计算剩余部分。
{
max_size = n;
}
else
{
max_size = my_rank * n / 4 + n / 4;
}
for (long long i = my_rank * n / 4; i < max_size; i++, factor = -factor)
{
my_sum += factor / (2 * (i + my_rank) + 1);
}
//printf("%.15lf\n", my_sum);

sem_wait(&sem); // 等待锁
sum += my_sum; // 临界状态
sem_post(&sem); // 释放锁

/******************************************************************/
return NULL;
} /* Thread_sum */

/*------------------------------------------------------------------
* Function: Serial_pi
* Purpose: Estimate pi using 1 thread
* In arg: n
* Return val: Estimate of pi using n terms of Maclaurin series
*/
double Serial_pi(long long n)
{
double sum = 0.0;
long long i;
double factor = 1.0;

for (i = 0; i < n; i++, factor = -factor)
{
sum += factor / (2 * i + 1);
}
return 4.0 * sum;

} /* Serial_pi */

/*------------------------------------------------------------------
* Function: Get_args
* Purpose: Get the command line args
* In args: argc, argv
* Globals out: thread_count, n
*/
void Get_args(int argc, char *argv[])
{
if (argc != 3)
Usage(argv[0]);
thread_count = strtol(argv[1], NULL, 10);
if (thread_count <= 0 || thread_count > MAX_THREADS)
Usage(argv[0]);
n = strtoll(argv[2], NULL, 10);
if (n <= 0)
Usage(argv[0]);
} /* Get_args */

/*------------------------------------------------------------------
* Function: Usage
* Purpose: Print a message explaining how to run the program
* In arg: prog_name
*/
void Usage(char *prog_name)
{
fprintf(stderr, "usage: %s <number of threads> <n>\n", prog_name);
fprintf(stderr, " n is the number of terms and should be >= 1\n");
fprintf(stderr, " n should be evenly divisible by the number of threads\n");
exit(0);
} /* Usage */

[学习]多线程锁
http://example.com/2021/04/11/学习/学习-多线程锁/
Author
peach-water
Posted on
April 11, 2021
Licensed under