操作系统原理作业(一):利用Linux多线程机制和积分中值定理计算π的值

作业题目

Write a program to figure out π with pthread. The formula is here as follows

You should choose the appropriate N and the number the threads and evaluate how do these two factors affect the performance. Try it in the multi-CPUs or multi-cores system if possible and compare the time consumed in the single CPU with one core system. Remember to add the option of -lpthread in gcc.

Programming guide:
Beginning Linux Programming 4e (Chapter 12: POSIX Threads)

设计思路

把线程的执行任务分成若干段,每个线程执行一段,最后将每一段得到的结果相加即可得到π的近似值。

具体实现

线程的操作和函数有:

(1)线程句柄: pthread_t。下面创建了4个指向线程的句柄:

1
2
const int numThreads = 4;
pthread_t hThread[numThreads];

(2)创建线程:pthread_create():

1
2
3
4
5
for (int i = 0; i < numThreads; i++)
{
//创建线程并且将thread函数传入
hThread[i] = pthread_create(&hThread[i], NULL, thread, &i);
}

同步和互斥

由于同一进程的线程之间大部分的数据都是共享的,在涉及到对共享数据进行读写操作时,就必须使用同步机制,否则就会造成线程们哄抢共享的数据,造成数据混乱甚至是丢失。在此,我们通过给线程加锁(互斥锁)来解决这一问题。

(1)互斥锁句柄:

1
pthread_mutex_t mut;

(2)加锁和解锁:

1
2
pthread_mutex_lock(&mut); //给线程加锁
pthread_mutex_unlock(&mut); //给线程解锁

(3)初始化互斥锁:

1
pthread_mutex_init(&mut, 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
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
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
static long N = 100000;
const int numThreads = 4;
double step;
double sum = 0.0;
pthread_mutex_t mut;
//依据计算Pi值的积分中值定理实现公式计算
void *thread(void *pArg)
{
double x;
int temp = *((int *)pArg);
int start = temp * (N / 4);
int end = start + N / 4;
printf("%d %d %d\n", temp, start, end);
for (int i = start; i < end; i++)
{
pthread_mutex_lock(&mut); //给线程加锁
x = (i + 0.5) * step;
sum = sum + 4.0 / (1.0 + x * x);
pthread_mutex_unlock(&mut); //给线程解锁
}
return 0;
}
int main()
{
clock_t t1 = clock();
pthread_t hThread[numThreads];
pthread_mutex_init(&mut, NULL); //初始化互斥锁
step = 1.0 / (double)N;
for (int i = 0;i < numThreads; i++)
{
//创建线程并且将thread函数传入
hThread[i] = pthread_create(&hThread[i], NULL, thread, &i);
}
double pi = step * sum;
printf("Pi = %12.9f\n", pi);
clock_t t2 = clock();
double duration = (double)(t2 - t1) / CLOCKS_PER_SEC;
printf("The whole computing time is %f seconds\n", duration);
return 0;
}

运行结果

  • 运行时链接-lpthread库,结果如下(设置计算的次数N=100000):

  • 经过分析发现,子线程在主线程完成的时候都还来不及执行,故所得π值为0。解决方法是在创建线程的时候等待1秒,以保证子线程能够得到执行。修改后的代码和运行结果如下:

    1
    2
    3
    4
    5
    6
    7
    for (int i = 0;i < numThreads; i++)
    {
    //创建线程并且将thread函数传入
    hThread[i] = pthread_create(&hThread[i], NULL, thread, &i);
    //让主线程等待1秒,确保子线程能够得到执行
    sleep(1);
    }

  • 将线程数减为2,运行结果如下:

  • 当线程数为1(单线程)时,运行结果如下:

完整代码

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
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
static long N = 100000;
const int numThreads = 4;
double step;
double sum = 0.0;
pthread_mutex_t mut;
//依据计算Pi值的积分中值定理实现公式计算
void *thread(void *pArg)
{
double x;
int temp = *((int *)pArg);
int start = temp * (N / 4);
int end = start + N / 4;
printf("%d %d %d\n", temp, start, end);
for (int i = start; i < end; i++)
{
pthread_mutex_lock(&mut); //给线程加锁
x = (i + 0.5) * step;
sum = sum + 4.0 / (1.0 + x * x);
pthread_mutex_unlock(&mut); //给线程解锁
}
return 0;
}
int main()
{
clock_t t1 = clock();
pthread_t hThread[numThreads];
pthread_mutex_init(&mut, NULL); //初始化互斥锁
step = 1.0 / (double)N;
for (int i = 0;i < numThreads; i++)
{
//创建线程并且将thread函数传入
hThread[i] = pthread_create(&hThread[i], NULL, thread, &i);
//让主线程等待1秒,确保子线程能够得到执行
sleep(1);
}
double pi = step * sum;
printf("Pi = %12.9f\n", pi);
clock_t t2 = clock();
double duration = (double)(t2 - t1) / CLOCKS_PER_SEC;
printf("The whole computing time is %f seconds\n", duration);
return 0;
}
坚持原创技术分享,您的支持将鼓励我继续创作!

热评文章