执行两个或多个相同类型的线程时出现问题-Pthread C

时间:2019-05-23 13:18:44

标签: c multithreading pthreads

我需要使用pthreads C库制作一个程序来处理线程。该任务的文本为:

  

有一条走廊,该走廊有一条单向两个方向的车道,   有两种类型的员工将越过走廊到达   相反的一面。有1类员工从左走   向右,然后键入2位从右到左的员工。在这   走廊里有一个服务员在没人的时候打扫这条走廊   通过它。清洁走廊时,双方的员工   双方等待其结束,否则,如果走廊被占用,则   员工说他不能打扫和睡一秒钟。

如果在执行程序时我想对经过的两个或更多相同类型的员工进行建模,就某种意义上说,当X型员工在走廊中时,一个或多个其他该类型的员工会到达并想利用第一个已经获得的通行证的许可,我该怎么办?

到目前为止,这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

//global variables 
int c1, c2; //counters for imp1, imp2
pthread_mutex_t m1, m2;
sem_t corridor; 
double clean = 0.5;

//implementation thread attendant
void *attendant(void *arg){
    sleep(1); //rest 1 seconds
    if (c1 == 0 && c2 == 0) {
        sem_wait(&corridor);
        printf("I'm starting to clean up\n");
        sleep(clean);
        printf("I finished cleaning\n");
        sem_post(&corridor);
    } else {
       printf("I can't clean, the corridor is busy\n");
    }

    return NULL;
}


//thread employee type 1
void *emp1(void *arg) {
    printf("I'm the number %d of em1\n", c1);
    pthread_mutex_lock(&m1); //beginning critical section
    c1++;                    //it increases to signal the presence of a thread of the same type that wants to enter the corridor
    if (c1 == 1){            //the thread is the only one in the corridor. Can pass
        printf ("I am the first of my group emp1\n");
        sem_wait(&corridor);  //takes possession of the corridor
    }
    pthread_mutex_unlock(&m1); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical section

    // invents "passage" function

    pthread_mutex_lock(&m1);  //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
    c1--;
    if (c1 == 0) {
        printf("I am the last of my group emp1\n");
        sem_post(&corridor);
    } //if c1 == 0, it is the last thread imp1 and releases the corridor
    pthread_mutex_unlock(&m1); //end critical section
    return NULL;
}


//thread employee type 2 
void *emp2(void *arg){
    printf("I'm the number %d of emp2\n", c2);
    pthread_mutex_lock(&m2); //beginning critical section
    c2++;                    //it increases to signal the presence of a thread of the same type that wants to enter the corridor
    if (c2 == 1) {           // the thread is the only one in the corridor. Can pass
        printf("I am the first of my group emp2\n");
        sem_wait(&corridor);  //takes possession of the corridor
    }
    pthread_mutex_unlock(&m2); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical sectionritica

    // invents "passage" function

    pthread_mutex_lock(&m2);  //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
    c2--;
    if (c2 == 0){
        printf ("I am the last of my group emp2\n");
        sem_post(&corridor);
    }//if c1 == 0, it is the last thread imp1 and releases the corridor
    pthread_mutex_unlock(&m2); //end critical section
    return NULL;
}


int main(int argc, char const *argv[]) {
    //pthread_t emp1, emp2, attendant;
    pthread_t idt;
    int r; //var random to create thread emp1 or emp2
    int i; //index 

    //variable initialization
    c1 = c2 = 0;
    pthread_mutex_init(&m1, NULL); 
    pthread_mutex_init(&m2, NULL);
    sem_init(&corridor,0,1); 

    pthread_create(&idt, NULL, attendant, NULL); 
    while (i < 40){
        sleep(1);
        r = rand() % 2;
        if (r == 0) {
            printf("Employee creation 1\n");
            pthread_create(&idt,NULL,emp1,NULL);
        } else {
            printf("Employee creation 2\n");
            pthread_create(&idt,NULL,emp2,NULL);
        }
        i++;
        pthread_join(idt, NULL);
    }
    return 0;
}

1 个答案:

答案 0 :(得分:3)

概述

为了实施

  

类型为X的员工在走廊中时,另外一名或多名   这类员工到达并想利用   第一个已经获得通过的许可

,您首先需要使这种情况甚至可能发生。目前,在任何给定的时间,您永远不会有一个以上的emp1emp2线程(合并),因为您在启动另一个线程之前先将它们加入。我认为对于此模拟,除了随机员工类型之外,您还希望在员工之间实现随机延迟,启动所有员工线程,并在它们之间添加这些延迟,然后仅在所有 all 之后加入他们启动。

此外,您必须实施某种穿越走廊的时间安排,这种时间安排有时至少比员工之间的延迟长,否则您仍然不太可能让一名员工到达而另一名员工在走廊中。

完成此操作后,您需要建立一个模型来模拟通过许可,或者更有效地建模当前在走廊中的人。此外,您需要以允许线程 block 的方式进行操作,直到至少有机会继续执行它们。

尽管信号量可以很好地用于某些线程同步问题,但是这种情况要求线程轮流或获取某些有限事物的所有权通常需要一个共享变量来表示拥有的事物/转向,而互斥量则可以保护对该变量的访问,以及条件变量可帮助线程等待机会继续进行。


实施方法

基本上需要跟踪两件事:

  1. 当前属于哪种员工类型的走廊(类型1,类型2,或服务员

    enum { ATTENDANT, TYPE1, TYPE2 } corridor_owner;
    

  2. 走廊上目前有多少员工。

    int corridor_occupancy;
    

此外,所有线程都需要依赖相同的互斥锁来保护对这些数据的访问

pthread_mutex_t corridor_mutex = PTHREAD_MUTEX_INITIALIZER;

他们同样需要共同的简历

pthread_cond_t corridor_cv = PTHREAD_COND_INITIALIZER;

有了这些,这是解决问题的一种合理的好方法:

当类型1或2的员工(线程)想要进入走廊时,他们必须遵循以下步骤:

  1. 获取互斥锁。
  2. 检查走廊当前是否由其他雇员类型拥有并已被占用:
    • 如果是,请等待CV,然后从等待返回后,重新开始步骤(2);
    • 如果不是,则为走廊声明其雇员类型(可能是多余的),并增加走廊的入住人数。
  3. 释放互斥锁

请注意,这允许多个相同类型的员工同时通过走廊。

当服务员要进入走廊时,它遵循不同的步骤:

  1. 获取互斥锁。
  2. 检查走廊当前是否由其他雇员类型拥有并已被占用:
    • 如果是,请首先释放互斥锁,然后睡眠一秒钟,然后返回到步骤(1);
    • 如果不是,请声明走廊的员工类型,增加走廊的占用人数,然后释放互斥锁。

任何类型的员工离开走廊时,都必须

  1. 获取互斥锁
  2. 减少入住人数
  3. 如果占用率为零,则唤醒所有等待CV的线程
  4. 释放互斥锁

此外,当话务员线程离开走廊时,它应该休眠一段时间,然后循环回以尝试再次清理-在您当前实现的时候,它只会清理一次。您还需要实现某种信号来使伴随线程停止,或者使其成为守护线程(而不是试图加入它)。