Linux多线程编程&多线程与信号量编程
本文最后更新于一年前或更久前,其中的信息可能已经有所发展或是发生改变。

多线程编程

实验题目

Project 2—Multithreaded Sorting Application

Write a multithreaded sorting program that works as follows: A list of integers is divided into two smaller lists of equal size. Two separate threads (which we will term sorting threads) sort each sublist using a sorting algorithm of your choice. The two sublists are then merged by a third thread—a merging thread —which merges the two sublists into a single sorted list.

Because global data are shared cross all threads, perhaps the easiest way

to set up the data is to create a global array. Each sorting thread will work on one half of this array. A second global array of the same size as the unsorted integer array will also be established. The merging thread will then merge the two sublists into this second array. Graphically, this program is structured according to Figure 4.20.

This programming project will require passing parameters to each of the sorting threads. In particular, it will be necessary to identify the starting index from which each thread is to begin sorting. Refer to the instructions in Project 1 for details on passing parameters to a thread.

The parent thread will output the sorted array once all sorting threads have exited.

解决方案

原理

题目要求:将一个数组分为两部分,之后用两个线程对这两部分分别进行排序,之后再使用一个线程将两个子数组合并,并且保持排序过的状态。

首先,读取用户的输入,先读取将要进行排序的数字的个数,之后读取对应的数量的数字。(体现在源代码中的main函数部分)

之后,将开始的数组均分为两部分,分别使用两个线程进行排序。笔者在这里使用了qsort函数进行子数组的排序。(也就是程序中的threadSorterOne和threadSorterTwo函数)

最后使用另外的线程,完成两个子数组的排序。(也就是threadConsolidator函数)

再main中通过

 

pthread_create(&thread_sorter_1, NULL, threadSorterOne, NULL);
pthread_create(&thread_sorter_2, NULL, threadSorterTwo, NULL);
pthread_join(thread_sorter_1, NULL);
pthread_join(thread_sorter_2, NULL);

pthread_create(&thread_consolidator, NULL, threadConsolidator, NULL);
pthread_join(thread_consolidator, NULL);

结果展示

源代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>

pthread_t thread_sorter_1, thread_sorter_2, thread_consolidator;

void *threadSorterOne(void *argv);
void *threadSorterTwo(void *argv);
void *threadConsolidator(void *argv);

int *arr, *arr1, *arr2;
int total, half;

int main(void)
{
    char buf[0x10];

    puts("Please input the amount of the nums you\'d like to sort:");
    scanf("%d", &total);
    if (total < 1)
    {
        puts("Invalid input!");
        exit(-1);
    }

    arr = (int *)malloc(sizeof(int) * total);
    if (arr == NULL)
    {
        puts("Error in malloc!");
        exit(-1);
    }

    for (int i = 0; i < total; i++)
    {
        scanf("%d", arr + i);
    }

    if (total != 1)
    {
        arr1 = (int *)malloc(sizeof(int) * total);
        arr2 = (int *)malloc(sizeof(int) * total);
        half = total / 2;
        memcpy(arr1, arr, sizeof(int) * half);
        memcpy(arr2, arr + half, sizeof(int) * (total - half));

        puts("The following nums will be sorted by thread 1:");
        for (int i = 0; i < half; i++)
            printf("%d ", arr1[i]);
        puts("");

        puts("The following nums will be sorted by thread 2:");
        for (int i = 0; i < total - half; i++)
            printf("%d ", arr2[i]);
        puts("");

        pthread_create(&thread_sorter_1, NULL, threadSorterOne, NULL);
        pthread_create(&thread_sorter_2, NULL, threadSorterTwo, NULL);
        pthread_join(thread_sorter_1, NULL);
        pthread_join(thread_sorter_2, NULL);

        pthread_create(&thread_consolidator, NULL, threadConsolidator, NULL);
        pthread_join(thread_consolidator, NULL);
    }

    puts("The result sorted out: ");
    for (int i = 0; i < total; i++)
        printf("%d ", arr[i]);
    puts("");

    return 0;
}

int compareInt(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

void *threadSorterOne(void *argv)
{
    qsort(arr1, half, sizeof(int), compareInt);
    pthread_exit(0);
}

void *threadSorterTwo(void *argv)
{
    qsort(arr2, total - half, sizeof(int), compareInt);
    pthread_exit(0);
}

void *threadConsolidator(void *argv)
{
    for (int i = 0, j = 0, ptr = 0; i != half || j != (total - half); ptr++)
        if (i != half)
        {
            if (j != (total - half))
            {
                if (arr1[i] < arr2[j])
                {
                    arr[ptr] = arr1[i++];
                }
                else
                {
                    arr[ptr] = arr2[j++];
                }
            }
            else
            {
                arr[ptr] = arr1[i++];
            }
        }
        else
        {
            arr[ptr] = arr2[j++];
        }
    pthread_exit(0);
}

多线程与信号量编程

实验题目

In Section 5.7.1, we presented a semaphore-based solution to the producer– consumer problem using a bounded buffer. In this project, you will design a programming solution to the bounded-buffer problem using the producer and consumer processes shown in Figures 5.9 and 5.10. The solution presented in Section 5.7.1 uses three semaphores: empty and full, which count the number of empty and full slots in the buffer, and mutex, which is a binary (or mutual exclusion) semaphore that protects the actual insertion or removal of items in the buffer. For this project, you will use standard counting semaphores for empty and full and a mutex lock, rather than a binary semaphore, to represent mutex. The producer and consumer—running as separate threads—will move items to and from a buffer that is synchronized with the empty, full, and mutex structures. You can solve this problem using either Pthreads or the Windows API.

解决方案

原理及关键源代码

既然是要进行生产者消费者模型的模拟,我们首先使用一个循环队列用以表示一个共享资源区。

#define BUFFER_SIZE 0x100
int items_queue[BUFFER_SIZE];
int front = 0, end = 0;

同时我们还需要设置相应的信号量与互斥锁,在这里我们将其设置为全局变量,其中empty与full使用信号量标识:在这里若是生产者数小于队列大小则将empty信号量的数量初始化为生产者数,否则初始化为队列大小,而full信号量的数量则初始化为0;队列相关操作则使用一个互斥锁标识即可保证线程安全。

Produce线程:

 

void * producerThread(void * args)
{
    int thread_no, item;

    pthread_mutex_lock(&pro_no_mutex);
    thread_no = ++producer_no;
    pthread_mutex_unlock(&pro_no_mutex);

    while (1)
    {
        if (rand() % 2)
        {
            sleep(rand() % 5); 
        }
        else
        {
            sem_wait(&empty);//empty--
            pthread_mutex_lock(&queue_mutex);
            do
            {
                item = rand() % 100; 
            } while (item == 0); // it's not so good for a lazy producer to produce nothing
            insertItem(item);
            printf(" producer %d produce: %d \n", thread_no, item);
            total_produce += item;
            pthread_mutex_unlock(&queue_mutex);
            sem_post(&full);//full++
        }
    }
}

Consumer线程:

void * consumerThread(void * args)
{
    int thread_no, item;

    pthread_mutex_lock(&con_no_mutex);
    thread_no = ++consumer_no;
    pthread_mutex_unlock(&con_no_mutex);

    while (1)
    {
        if (rand() % 2)
        {
            sleep(rand() % 5); 
        }
        else
        {
            sem_wait(&full);//full--
            pthread_mutex_lock(&queue_mutex);
            item = removeItem();
            printf(" consumer %d consumes: %d \n", thread_no, item);
            total_consume += item;
            pthread_mutex_unlock(&queue_mutex);
            sem_post(&empty);//empty++
        }
    }
}

结果展示

通过管道将输出结果保存到了Exp4.log中,Exp4.log的文件全文将放在实验报告末尾。

在exp4.log中我们可以看到,生产者和消费者生产和消费的资源达到了平衡。

完整源代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <semaphore.h>

#define BUFFER_SIZE 0x100

int items_queue[BUFFER_SIZE];
pthread_mutex_t queue_mutex, con_no_mutex, pro_no_mutex;
sem_t empty, full;

int front = 0, end = 0;
int producer_nums, consumer_nums;
int producer_no = 0, consumer_no = 0;
int running_time;
int total_consume = 0, total_produce = 0;

pthread_t * consumer, *producer;

void insertItem(int item)
{
    items_queue[front++] = item;
    front = front % BUFFER_SIZE;
}

int removeItem(void)
{
    end =end % BUFFER_SIZE;
    return items_queue[end++];
}

void * consumerThread(void * args)
{
    int thread_no, item;

    pthread_mutex_lock(&con_no_mutex);
    thread_no = ++consumer_no;
    pthread_mutex_unlock(&con_no_mutex);

    while (1)
    {
        if (rand() % 2)
        {
            sleep(rand() % 5); 
        }
        else
        {
            sem_wait(&full);//full--
            pthread_mutex_lock(&queue_mutex);
            item = removeItem();
            printf(" consumer %d consumes: %d \n", thread_no, item);
            total_consume += item;
            pthread_mutex_unlock(&queue_mutex);
            sem_post(&empty);//empty++
        }
    }
}

void * producerThread(void * args)
{
    int thread_no, item;

    pthread_mutex_lock(&pro_no_mutex);
    thread_no = ++producer_no;
    pthread_mutex_unlock(&pro_no_mutex);

    while (1)
    {
        if (rand() % 2)
        {
            sleep(rand() % 5); 
        }
        else
        {
            sem_wait(&empty);//empty--
            pthread_mutex_lock(&queue_mutex);
            do
            {
                item = rand() % 100; 
            } while (item == 0); // it's not so good for a lazy producer to produce nothing
            insertItem(item);
            printf(" producer %d produce: %d \n", thread_no, item);
            total_produce += item;
            pthread_mutex_unlock(&queue_mutex);
            sem_post(&full);//full++
        }
    }
}

int main(int argc, char ** argv)
{
    if (argc != 4)
    {
        puts("Usage: ./Exp4 time producer_nums consumer_nums");
        exit(0);
    }

    running_time = atoi(argv[1]);
    producer_nums = atoi(argv[2]);
    consumer_nums = atoi(argv[3]);
    if (running_time < 0 || producer_nums < 0 || consumer_nums < 0)
    {
        puts("Invalid arguments!");
        return 0;
    }

    sem_init(&empty, 0, (BUFFER_SIZE > producer_nums ? producer_nums : BUFFER_SIZE));
    sem_init(&full, 0, 0);
    pthread_mutex_init(&queue_mutex, NULL);
    pthread_mutex_init(&con_no_mutex, NULL);
    pthread_mutex_init(&pro_no_mutex, NULL);

    srand(time(NULL));

    consumer = (pthread_t*) malloc(sizeof(pthread_t) * consumer_nums);
    producer = (pthread_t*) malloc(sizeof(pthread_t) * producer_nums);

    for (int i = 0; i < consumer_nums;i++)
        pthread_create(consumer + i, NULL, consumerThread, NULL);

    for (int i = 0; i < producer_nums;i++)
        pthread_create(producer + i, NULL, producerThread, NULL);

    sleep(running_time);
    pthread_mutex_lock(&queue_mutex);
    printf("totally produce: %d, totally consume: %d\n", total_produce, total_consume);
    exit(0);
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇