简单多线程编程中的切换问题(os-hw4)

写一个 2 线程的程序:

首先生成一个从 1 到 1000 万的整数数组,然后用两个线程分别计算数组奇数部分和偶数部分的和,并打印出总的和。(采用 pthread API )

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
#define N 10000000
#define STEP 2

long int integer[N];

void *sumf(void *t)
{
    extern long int integer[N];
    int ini = *(int *)t;
    if (integer[ini] % STEP)
        printf("odd sum");
    else
        printf("even sum");
    long int s = 0;
    for (int i = ini; i < N; i += STEP)
    {
        s = s + integer[i];
    }
    printf(": %ld	", s);
}

int main()
{
    // array of integers
    extern long int integer[N];
    for (int i = 0; i < N; i++)
        integer[i] = i + 1;
    // sample output
    long int s_spl = 0;
    for (int i = 0; i < N; i += STEP)
        s_spl += integer[i];
    printf("sample:	odd sum: %ld", s_spl);
    s_spl = 0;
    for (int i = 1; i < N; i += 2)
        s_spl += integer[i];
    printf("	even sum: %ld
", s_spl);

    // 2 threads
    printf("2 threads:
	");
    pthread_t th1, th2;
    // time1
    struct timeval t0, t1;
    time_t sec0;
    suseconds_t msec0;
    gettimeofday(&t0, NULL);

    int para0 = 0, para1 = 1;
    pthread_create(&th1, NULL, sumf, (void *)&para0);
    pthread_create(&th1, NULL, sumf, (void *)&para1);
    pthread_join(th1, NULL);
    pthread_join(th2, NULL);
    // time2
    gettimeofday(&t1, NULL);
    sec0 = t1.tv_sec - t0.tv_sec;
    msec0 = t1.tv_usec - t0.tv_usec;
    printf("
	(glibc) time used:%ld.%ldms
", sec0 * 1000, msec0);
    return 0;
}

编译执行的结果:

$ gcc hw4.c -lm -O3 -g -o hw4 -lpthread # 在最后链接pthread的动态库
$ ./hw4    
sample: odd sum: 25000000000000 even sum: 25000005000000
2 threads:
        odd sumeven sum: 25000000000000 : 25000005000000
        (glibc) time used:0.4862ms

可以发现最后输出格式略奇怪,检查 sumf 函数,发现它的结构大致为:if-calc()-prtf(res),由于 pthread_create 产生的线程可能在执行中随机切换(即线程内有序,线程间随机),因此有可能执行完 th1 的 if 段后切换到 th2 执行,从而使输入格式不符合预期(在程序上并没有毛病)。

为了改善这种情况,注意到 printf 提供的是封装的内核态函数的用户态接口,因此考虑把 if 的 print 和 res 的print合并使用 printf,新的 sumf 如下:

void *sumf(void *t)
{
    extern long int integer[N];
    int ini = *(int *)t;
      // 把求和放在前面
    long int s = 0;
    for (int i = ini; i < N; i += STEP)
    {
        s = s + integer[i];
    }
      // 合并输出想要的结果
    if (integer[ini] % STEP)
        printf("odd sum: %ld	", s);
    else
        printf("even sum: %ld	", s);
}

得到的结果即修正为:

$ gcc hw4.c -lm -O3 -g -o hw4 -lpthread
$ ./hw4
sample: odd sum: 25000000000000 even sum: 25000005000000
2 threads:
        odd sum: 25000000000000 even sum: 25000005000000
        (glibc) time used:0.4958ms

该修改的效用得到验证。

原文地址:https://www.cnblogs.com/ria2020/p/13785339.html