多线程客户端-服务器同步问题

时间:2021-05-25 17:37:48

标签: c multithreading

我正在尝试构建多线程客户端-服务器项目,其中:每个客户端在两个队列中插入姓名和姓氏,一个用于姓名,另一个用于姓氏。插入后,我创建 N 个工作线程以查找 2 个队列之间的匹配项。如果找到匹配项(姓名 == 姓氏),则线程必须删除两个队列中匹配的节点。

我在考虑两种可能的同步方案:

  1. 一个线程正在工作,N-1 个线程被挂起,以便在删除匹配节点后更新队列。但我认为它效率低下,因为我没有并行线程执行。

  2. 2 个线程只更新队列,N-2 个线程只同时读取队列,我只锁定正在读取或删除的节点。

第二个场景的执行如下,但我对嵌套锁感到困惑。

以下代码用于服务器。客户端只在队列中插入名称。

updateOne线程一直在等待,直到条件变量update变为1。如果为1,则删除匹配的节点并转为条件变量update到 0 并释放 func 线程。

对于所需的同步场景,我需要两件事:

  1. func 线程连续运行,直到找到 3 个匹配。如果一个节点被删除,他们必须读取队列的其余部分,而不是被挂起

问题 1:**我怎样才能让其余的 func 线程正常工作而不被挂起? ** 2) updateOne 线程可以获取reader 锁以遍历队列并删除匹配的节点,而func 线程读取其余节点

问题 2如何使用 readerLock 来锁定节点级别而不是队列级别?

问题 3pop_from_index 是否正常工作?


#include "list.h"


typedef struct info {
    node *info_buy;
    node *info_sell;
}info;
int update = 0;
int matches = 0;
pthread_mutex_t reader_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t update_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;

void *updateOne (void *args){

    info *arg = (info *)args;
    node *temp_buy = arg->info_buy;
    node *temp_sell = arg->info_sell;
    printf("waiting\n");
    while (1){
        pthread_mutex_lock(&update_lock);

        while (update != 1){
            pthread_cond_wait(&condition, &update_lock);
        }

        printf("woke up\n");

        node *tb = temp_buy;
        node *ts = temp_sell;


        int index_to_delete = -1;
        while (tb != NULL){
            if (tb->valid == 0){
                index_to_delete = tb->n;
                printf("Index buy %d\n", tb->n);
                pop_from_index(&temp_buy, index_to_delete);
            }
            tb = tb->next;
        }
        printList(temp_buy);

        while (ts != NULL){
            if (ts->valid == 0){
                index_to_delete = ts->n;
                printf("Index sell %d\n", ts->n);

                pop_from_index(&temp_sell, index_to_delete);

            }
            ts = ts->next;
        }
        printList(temp_sell);

        update = 0;
        pthread_cond_broadcast(&condition);
        pthread_mutex_unlock(&update_lock);
    }

    return NULL;
}

void *func(void *args)
{
    // Store the value argument passed to this thread

    /*info *n = (info*) args;
    pthread_mutex_lock(&reader_lock);
    int index = -1;
    node *t1 = n->info_buy;
    while (t1 != NULL){
        node *t2 = n->info_sell;
        while (t2 != NULL){

            if (strcmp(t1->command, t2->command) == 0){

                pthread_mutex_lock(&update_lock);

                update = 1;

                pthread_cond_broadcast(&condition);

                t1->valid = 1;

                t2->valid = 1;

                pthread_mutex_unlock(&update_lock);

                break;
            }
            t2 = t2->next;
        }
        t1 = t1->next;

    }
    pthread_mutex_unlock(&reader_lock);
*/



    info *queues = (info *) args;
    node *buy = queues->info_buy;
    node *sell = queues->info_sell;


    while (1){
        pthread_mutex_lock(&reader_lock);

        node *tb = buy;

        while (tb != NULL){

            node *ts = sell;
            while (ts != NULL){
                pthread_mutex_lock(&update_lock);

                sleep(1);
                while (update == 1){
                    pthread_cond_wait(&condition, &update_lock);
                }

                if (strcmp(ts->command, tb->command) == 0){
                    matches++;
                    if (matches >= 3){
                        break;
                    }
                    printf("*** Matched! ***\n");
                    printf("Matched pair --> (%s, %s)\n", ts->command, tb->command);
                    ts->valid = 0;
                    tb->valid = 0;

                    update = 1;
                    pthread_cond_broadcast(&condition);
                }
                ts = ts->next;
                pthread_mutex_unlock(&update_lock);

            }
            tb = tb->next;
        }
        if (matches >= 3){
            break;
        }
        pthread_mutex_unlock(&reader_lock);
    }
    return NULL;
}

void *destroy_list(void *args){

    pthread_mutex_lock(&update_lock);

    info *queues = (info *)args;

    destroyList(&(queues->info_buy));

    destroyList(&(queues->info_sell));

    pthread_mutex_unlock(&update_lock);

    return NULL;
}

int main(){

    pthread_t workingThreads[5];
    pthread_t updateThreads[2];
    pthread_t destroy[2];
    pthread_cond_init(&condition, NULL);

    if (pthread_mutex_init(&reader_lock, NULL) != 0) {
        printf("\n mutex init has failed\n");
        return 1;
    }

    if (pthread_mutex_init(&update_lock, NULL) != 0) {
        printf("\n mutex init has failed\n");
        return 1;
    }

    node *sell = NULL;
    node *buy = NULL;

    push(&sell, "Maria");
    push(&sell, "Sam");
    push(&sell, "Tom");
    push(&sell, "Takis");

    push(&buy, "Mary");
    push(&buy, "Edgar");
    push(&buy, "Marx");
    push(&buy, "Takis");
//
//

    info *ptr = malloc(sizeof(info));

    ptr->info_buy = sell;
    ptr->info_sell = buy;

    for (int i = 0; i < 1; i++){
        pthread_create(&(updateThreads[i]), NULL, updateOne, ptr);
    }

    pthread_create(&(workingThreads[0]), NULL, func, ptr);
    pthread_create(&(workingThreads[1]), NULL, func, ptr);
    pthread_create(&(workingThreads[2]), NULL, func, ptr);
    pthread_create(&(workingThreads[3]), NULL, func, ptr);
    pthread_create(&(workingThreads[4]), NULL, func, ptr);

//    for (int i = 0; i < 2; i++){
//        pthread_create(&(destroy[i]), NULL, destroy_list, ptr);
//    }


    for (int i = 0; i < 2; i++){
        pthread_join(updateThreads[i], NULL);
    }
    for (int i = 0; i < 5; i++){
        pthread_join(workingThreads[i], NULL);
    }



    pthread_mutex_destroy(&reader_lock);
    pthread_mutex_destroy(&update_lock);
    pthread_cond_destroy(&condition);

    destroyList(&sell);
    destroyList(&buy);

    return 0;
}

void pop_from_index (node **head, int index){
    


    if ((*head) == NULL){
        return;
    }

    node * temp = (*head);

    if (index == 0){
        *head = temp->next;

        free(temp);

        return;
    }

    for (int i=0; temp!=NULL && i< index - 1; i++){
        temp = temp->next;

    }
    
    // If position is more than number of nodes
    if (temp == NULL || temp->next == NULL)
        return;

    // Node temp->next is the node to be deleted
    // Store pointer to the next of node to be deleted
    struct node *next = temp->next->next;

    free(temp->next);  // Free memory

    temp->next = next;  // Unlink the deleted node from list


1 个答案:

答案 0 :(得分:0)

我认为您正在寻找互斥锁。它非常复杂,但简单地说,它是一种锁定/解锁机制,适用于多个线程尝试访问相同数据的情况,或者换句话说:线程之间的同步。我认为 this article 会让您对这个主题有一个很好的了解。

相关问题