有关使用信号量执行线程的操作系统作业问题

时间:2019-10-28 19:49:41

标签: linux sorting parallel-processing pthreads semaphore

我正在做作业,要求是使用Pthread并使用信号量来锁定和解锁它们以实现并行合并排序。

由于我已经完成了单线程部分,因此只能查看函数名称Multi____并忽略Single _____。

我在多线程部分遇到了问题。我在第227行发信号通知主线程(sem [1]),它应该进入函数'void * MultiPartition'。

在此函数中,它给arg [id * 2]和arg [id * 2 + 1]赋值。

例如,arg [1]将为arg [2]和arg [3]赋值,然后通过sem_post发出信号,通知线程[2]和线程[3]。

而且似乎不起作用。

所以我在第111行中使用cout << "partition id = " << id << ", head = " << head << ", mid = " << mid << ", tail = " << tail << "\n";来检查会发生什么情况。

看起来真的很奇怪。有时会输出

partition id = 1, head = 0, mid = 7, tail = 15 
partition id = 2, head = 0, mid = 3, tail = 7 

并被卡住,但是程序没有退出。意味着我需要按Ctrl ^ C退出程序。

有时会输出

partition id = 1, head = 0, mid = 7, tail = 15
partition id = 2, head = 0, mid = 3, tail = 7
partition id = 3, head = 8, mid = 11, tail = 15
partition id = 4, head = 0, mid = 1, tail = 3

也被卡住了。

我很好奇其他线程在哪里?

如果显示id = 4,它将通常运行气泡id = 8。

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <fstream>
#include <sys/time.h>
#include <unistd.h>
using namespace std;
//Pthread_create, pthread_exit  *don't use pthread_join
//sem_init, sem_wait, sem_post, sem_getvalue, sem_destroy

//Enter input file name: test.txt 
//MT sorting used x secs
//ST sorting used x secs

// g++ -o os_hw3.out os_hw3.cpp -pthread

typedef struct{
    int head;
    int mid;
    int tail;
    int id;
}arguments;

//declare global variables
sem_t sem[16]; // use id = 1 ~ 15 
sem_t final; // the final semaphore signal that indicate all threads finished.
int* s1, * s2; // two array for single and multiple
arguments arg[16]; 

void swap(int* x, int* y) {
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

void *MultiMerge(void* argid) {
    int id = *(int*)argid;
    sem_wait(&sem[id]);
    sem_wait(&sem[id]);
    int head = arg[id].head, mid = arg[id].mid, tail = arg[id].tail;
    //cout << "merge id = " << id << ", head = " << head << ", mid = " << mid << ", tail = " << tail << "\n";
    int lenA = mid - head + 1;
    int lenB = tail - (mid + 1) + 1;
    int A[lenA];
    int B[lenB];

    for (int i = 0; i < lenA; i++) {
        A[i] = *(s1 + head + i);
    }
    for (int j = 0; j < lenB; j++) {
        B[j] = *(s1 + mid + 1 + j);
    }
    int i = 0, j = 0, k = 0;
    while (i < lenA && j < lenB) {
        if (A[i] < B[j]) {
            *(s1 + head + k) = A[i];
            i++;
        }
        else {
            *(s1 + head + k) = B[j];
            j++;
        }
        k++;
    }
    while (i < lenA) {
        *(s1 + head + k) = A[i];
        i++;
        k++;
    }
    while (j < lenA) {
        *(s1 + head + k) = B[j];
        j++;
        k++;
    }
    sem_post(&sem[id / 2]); // signal the upper level

    if (id == 1) {
        fstream fout;
        fout.open("output1.txt", ios::out);
        for (i = 0; i < arg[1].tail + 1; i++)
            fout << *(s2 + i);
        fout.close();
        sem_post(&final);
    }
}

void *MultiBubble(void *argid) {
    int id = *(int*)argid;
    sem_wait(&sem[id]);
    //cout << "bubble id = " << id << ", head = " << arg[id].head << ", tail = " << arg[id].tail << "\n";
    for (int i = arg[id].tail; i > 0; --i) {
        for (int j = arg[id].head; j < i; ++j) {
            if (*(s2 + j) > * (s2 + j + 1)) {
                swap((s2 + j), (s2 + j + 1));

            }
        }
    }
    for (int i = arg[id].head; i <= arg[id].tail; i++) {
        cout << *(s2 + i) << " ";
    }
    cout << "\n";
    sem_post(&sem[id / 2]);
}

void *MultiPartition(void* argid) {
    int id = *(int*)argid;
    sem_wait(&sem[id]);
    int head = arg[id].head, mid = arg[id].mid, tail = arg[id].tail;
    cout << "partition id = " << id << ", head = " << head << ", mid = " << mid << ", tail = " << tail << "\n";

    arg[id * 2].head = arg[id].head;
    arg[id * 2].tail = arg[id].mid;
    arg[id * 2].mid = (arg[id * 2].head + arg[id * 2].tail) / 2;

    arg[id * 2 + 1].head = arg[id].mid + 1;
    arg[id * 2 + 1].tail = arg[id].tail;
    arg[id * 2 + 1].mid = (arg[id * 2 + 1].head + arg[id * 2 + 1].tail) / 2;

    sem_post(&sem[id * 2]);
    sem_post(&sem[id * 2 + 1]);
}

void SingleMerge(int* s1, int head, int mid, int tail) {
    int lenA = mid - head + 1;
    int lenB = tail - (mid + 1) + 1;
    int A[lenA];
    int B[lenB];

    for (int i = 0; i < lenA; i++) {
        A[i] = *(s1 + head + i);
    }
    for (int j = 0; j < lenB; j++) {
        B[j] = *(s1 + mid + 1 + j);
    }
    int i = 0, j = 0, k = 0;
    while (i < lenA && j < lenB) {
        if (A[i] < B[j]) {
            *(s1 + head + k) = A[i];
            i++;
        }
        else {
            *(s1 + head + k) = B[j];
            j++;
        }
        k++;
    }
    while (i < lenA) {
        *(s1 + head + k) = A[i];
        i++;
        k++;
    }
    while (j < lenA) {
        *(s1 + head + k) = B[j];
        j++;
        k++;
    }
}

int SingleBubble(int* s1, int head, int tail) {
    for (int i = tail; i > 0; --i) {
        for (int j = head; j < i; ++j) {
            if (*(s1 + j) > *(s1 + j + 1)) {
                swap((s1 + j), (s1 + j + 1));
            }
        }
    }
}

void SinglePartition(int* s1, int head, int tail, int times) {
    if (head <= tail) {
        int mid = (head + tail) / 2;
        if (times < 3) {
            SinglePartition(s1, head, mid, ++times);
            SinglePartition(s1, mid + 1, tail, ++times);
        }
        else {
            SingleBubble(s1, head, tail);
        }
        SingleMerge(s1, head, mid, tail);   
    }
}

int main() {
    char filename[100];
    int num;
    struct timeval Tstart, Tend;
    cout << "Enter the input file name: ";
    cin >> filename;
    fstream file, fout;
    file.open(filename, ios::in);
    if (!file) {
        cout << "Read File Error.\n";
        return -1;
    }
    else {

        file >> num;
        s1 = new int[num];
        s2 = new int[num];
        for (int i = 0; i < num; i++) {
            file >> *(s1 + i);
            *(s2 + i) = *(s1 + i);
        }
        file.close();

    }
    //SINGLE THREAD
    gettimeofday(&Tstart, 0);
    SinglePartition(s1, 0, num - 1, 0);
    gettimeofday(&Tend, 0);
    fout.open("output2.txt", ios::out);
    for (int i = 0; i < num; i++)
        fout << *(s1 + i) << " ";
    fout.close();
    double Tdifference = (Tend.tv_sec - Tstart.tv_sec) + (Tend.tv_usec - Tstart.tv_usec) / 1000000.0;
    cout << "Single thread cost " << Tdifference << " s\n";
    //MULTI THREAD
    gettimeofday(&Tstart, 0);
    arg[1].head = 0;
    arg[1].tail = num - 1;
    arg[1].mid = (arg[1].head + arg[1].tail) / 2;
    pthread_t thread[16];
    sem_init(&final, 0, 0);
    sem_post(&sem[1]);
    for (int i = 1; i < 16; i++){
        arg[i].id = i;
        sem_init(&sem[i], 0, 0);
        if (i < 8) {
            if(i == 1)  
                sem_post(&sem[1]); // call the master thread
            pthread_create(&thread[i], NULL, MultiPartition, &arg[i].id);
        }
        else
            pthread_create(&thread[i], NULL, MultiBubble, &arg[i].id);
    }
    for (int i = 7; i > 0; i--) {
        pthread_create(&thread[i], NULL, MultiMerge, &arg[i].id);
    }

    sem_wait(&final);

    gettimeofday(&Tend, 0);
    Tdifference = (Tend.tv_sec - Tstart.tv_sec) + (Tend.tv_usec - Tstart.tv_usec) / 1000000.0;
    cout << "Multi thread cost " << Tdifference << " s\n";
    delete s1, s2;

    for (int i = 0; i < 16; i++) 
        sem_destroy(&sem[i]);
    sem_destroy(&final);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

我自己修复了。

for (int i = 7; i > 0; i--) {
        pthread_create(&thread[i], NULL, MultiMerge, &arg[i].id);
    }

上面的部分将面对下面的部分。

for (int i = 1; i < 16; i++){
        arg[i].id = i;
        sem_init(&sem[i], 0, 0);
        if (i < 8) {
            if(i == 1)  
                sem_post(&sem[1]); // call the master thread
            pthread_create(&thread[i], NULL, MultiPartition, &arg[i].id);
        }

MultiMerge和MultiPartition都具有

sem_wait(&sem[id]);

因此,如果我认为sem [id]的值!= 0,那么我不知道该执行哪个函数。


我删除

for (int i = 7; i > 0; i--) {
        pthread_create(&thread[i], NULL, MultiMerge, &arg[i].id);
    }

并添加

MultiMerge(&arg[id].id);

在MultiPartition底部调用MultiMerge,可以解决我的问题。