交替打印字符串

交替打印字符串

描述

编写一个可以从 1 到 n 输出代表这个数字的字符串的程序,但是:

如果这个数字可以被 3 整除,输出 "fizz"。
如果这个数字可以被 5 整除,输出 "buzz"。
如果这个数字可以同时被 3 和 5 整除,输出 "fizzbuzz"。

例如,当 n = 15,输出: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz。

假设有这么一个类:

class FizzBuzz {
public FizzBuzz(int n) { ... } // constructor
public void fizz(printFizz) { ... } // only output "fizz"
public void buzz(printBuzz) { ... } // only output "buzz"
public void fizzbuzz(printFizzBuzz) { ... } // only output "fizzbuzz"
public void number(printNumber) { ... } // only output the numbers
}

请你实现一个有四个线程的多线程版 FizzBuzz, 同一个 FizzBuzz 实例会被如下四个线程使用:

线程A将调用 fizz() 来判断是否能被 3 整除,如果可以,则输出 fizz。
线程B将调用 buzz() 来判断是否能被 5 整除,如果可以,则输出 buzz。
线程C将调用 fizzbuzz() 来判断是否同时能被 3 和 5 整除,如果可以,则输出 fizzbuzz。
线程D将调用 number() 来实现输出既不能被 3 整除也不能被 5 整除的数字。

方案一(结果超时,暂时还不知道为什么)

  • 使用信号量和互斥锁共同控制
typedef struct {
    int n;
    int current;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} FizzBuzz;

FizzBuzz* fizzBuzzCreate(int n) {
    FizzBuzz* obj = (FizzBuzz*) malloc(sizeof(FizzBuzz));
    obj->n = n;
    obj->current = 1;
    pthread_mutex_init(&obj->mutex, NULL);
    pthread_cond_init(&obj->cond, NULL);
    return obj;
}

// printFizz() outputs "fizz".
void fizz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->current > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while(obj->current % 3 != 0 || obj->current % 5 == 0)
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->current > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printFizz();
        obj->current++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// printBuzz() outputs "buzz".
void buzz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->current > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while(obj->current % 3 == 0 || obj->current % 5 != 0)
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->current > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printBuzz();
        obj->current++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// printFizzBuzz() outputs "fizzbuzz".
void fizzbuzz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->current > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while(obj->current % 3 != 0 || obj->current % 5 != 0)
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->current > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printFizzBuzz();
        obj->current++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// You may call global function `void printNumber(int x)`
// to output "x", where x is an integer.
void number(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->current > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while(obj->current % 3 == 0 || obj->current % 5 == 0)
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->current > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printNumber(obj->current);
        obj->current++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

void fizzBuzzFree(FizzBuzz* obj) {
    if(obj)
    {
        pthread_mutex_destroy(&obj->mutex);
        pthread_cond_destroy(&obj->cond);
        free(obj);
        obj = NULL;
    }
}

方案二(报错:You called method from wrong thread. Exiting.)

  • 由于每个函数不是打印一次,所以需要用while循环while(obj->index <= obj->n) {}
  • 由于是满足一定的条件才能打印,因此调用pthread_cond_wait阻塞住当前线程,如果满足条件,才能往下运行
  • 如果当前索引越界了,则停止线程,这一点很重要,不然会导致超时
  • 如果索引有效,则打印相关的值,并唤醒其他线程工作
  • 最后唤醒所有的线程,让每个线程结束运行。
typedef struct {
    int n;
    int index;
    pthread_mutex_t mutex;
    pthread_cond_t fizzs,buzzs,fizzbuzzs,numbers;
} FizzBuzz;

FizzBuzz* fizzBuzzCreate(int n) {
    FizzBuzz* obj = (FizzBuzz*) malloc(sizeof(FizzBuzz));
    obj->n = n;
    obj->index = 1;
    pthread_mutex_init(&obj->mutex, NULL);
    pthread_cond_init(&obj->fizzs,NULL);
    pthread_cond_init(&obj->buzzs,NULL);
    pthread_cond_init(&obj->fizzbuzzs,NULL);
    pthread_cond_init(&obj->numbers,NULL);
    return obj;
}

void process (FizzBuzz* obj) {

    if (obj->index > obj->n) {
        pthread_cond_signal(&obj->fizzbuzzs);
        pthread_cond_signal(&obj->fizzs);
        pthread_cond_signal(&obj->buzzs);
        pthread_cond_signal(&obj->numbers);
    }

    if (0 == obj->index%3 && 0 == obj->index%5) {
        pthread_cond_signal(&obj->fizzbuzzs);
    } else if (0 == obj->index%3) {
        pthread_cond_signal(&obj->fizzs);
    } else if (0 == obj->index%5) {
        pthread_cond_signal(&obj->buzzs);
    } else {
        pthread_cond_signal(&obj->numbers);
    }
}

// printFizz() outputs "fizz".
void fizz(FizzBuzz* obj) {
    while(obj->index <= obj->n) {

        pthread_mutex_lock(&obj->mutex);

        while (0 != obj->index%3 && obj->index <= obj->n) {
            pthread_cond_wait(&obj->fizzs,&obj->mutex);
        }

        if (obj->index > obj->n) {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        } else {
            printFizz();
            obj->index++;

            process(obj);
            
            pthread_mutex_unlock(&obj->mutex);
        }
    }
}

// printBuzz() outputs "buzz".
void buzz(FizzBuzz* obj) {
    while(obj->index <= obj->n) {

        pthread_mutex_lock(&obj->mutex);

        while (0 != obj->index%5 && obj->index <= obj->n) {
            pthread_cond_wait(&obj->buzzs,&obj->mutex);
        }

        if (obj->index > obj->n) {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        } else {
            printBuzz();
            obj->index++;

            process(obj);

            pthread_mutex_unlock(&obj->mutex);
        }
    }
}

// printFizzBuzz() outputs "fizzbuzz".
void fizzbuzz(FizzBuzz* obj) {
    while(obj->index <= obj->n) {

        pthread_mutex_lock(&obj->mutex);

        while (0 != obj->index%5 && 0 != obj->index%3 && obj->index <= obj->n) {
            pthread_cond_wait(&obj->fizzbuzzs,&obj->mutex);
        }

        if (obj->index > obj->n) {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        } else {
            printFizzBuzz();
            obj->index++;

            process(obj);

            pthread_mutex_unlock(&obj->mutex);
        }
    }
}

// You may call global function `void printNumber(int x)`
// to output "x", where x is an integer.
void number(FizzBuzz* obj) {
    while(obj->index <= obj->n) {

        pthread_mutex_lock(&obj->mutex);

        while((0 == obj->index%3 || 0 == obj->index%5) && obj->index <= obj->n) {
            pthread_cond_wait(&obj->numbers,&obj->mutex);
        }

        if (obj->index > obj->n) {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        } else {
            printNumber(obj->index);
            obj->index++;

            process(obj);

            pthread_mutex_unlock(&obj->mutex);
        }
    }
}

void fizzBuzzFree(FizzBuzz* obj) {
    if (NULL != obj) {
        pthread_mutex_destroy(&obj->mutex);
        pthread_cond_destroy(&obj->fizzs);
        pthread_cond_destroy(&obj->buzzs);
        pthread_cond_destroy(&obj->fizzbuzzs);
        pthread_cond_destroy(&obj->numbers);
    }
}

方案三

typedef struct {
    int n;
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    int cnt;
} FizzBuzz;

FizzBuzz* fizzBuzzCreate(int n) {
    FizzBuzz* obj = (FizzBuzz*) malloc(sizeof(FizzBuzz));
    obj->n = n;
    obj->cnt = 1;
    pthread_cond_init(&obj->cond, NULL);
    pthread_mutex_init(&obj->mutex, NULL);
    return obj;
}

// printFizz() outputs "fizz".
void fizz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->cnt > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while((obj->cnt % 3 != 0) || (obj->cnt % 5 == 0))
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->cnt > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printFizz();
        obj->cnt++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// printBuzz() outputs "buzz".
void buzz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->cnt > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while((obj->cnt % 3 == 0) || (obj->cnt % 5 != 0))
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->cnt > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printBuzz();
        obj->cnt++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// printFizzBuzz() outputs "fizzbuzz".
void fizzbuzz(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->cnt > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while((obj->cnt % 3 != 0) || (obj->cnt % 5 != 0))
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->cnt > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printFizzBuzz();
        obj->cnt++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

// You may call global function `void printNumber(int x)`
// to output "x", where x is an integer.
void number(FizzBuzz* obj) {
    while(1)
    {
        pthread_mutex_lock(&obj->mutex);
        if(obj->cnt > obj->n)
        {
            pthread_mutex_unlock(&obj->mutex);
            pthread_exit(NULL);
        }
        while((obj->cnt % 3 == 0) || (obj->cnt % 5 == 0))
        {
            pthread_cond_wait(&obj->cond, &obj->mutex);
            if(obj->cnt > obj->n)
            {
                pthread_mutex_unlock(&obj->mutex);
                pthread_exit(NULL);
            }
        }
        printNumber(obj->cnt);
        obj->cnt++;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

void fizzBuzzFree(FizzBuzz* obj) {
    if(obj)
    {
        pthread_cond_destroy(&obj->cond);
        pthread_mutex_destroy(&obj->mutex);
        free(obj);
        obj = NULL;
    }
}

猜你喜欢

转载自www.cnblogs.com/beimangshanxiaoqigui/p/12530513.html