maxneedwill 2020-01-18 09:20 采纳率: 0%
浏览 381

Python多线程通信问题

新人第一次提问, 最近在学习Python多线程, notify()与wait()语句。这是我写的一个作业, 要求是:
现在的你,是一个农场主。农场中养着10头小牛,牛吃草长大,但只有当下雨的时候草才会长大,每天有20%的概率下雨,草经过3次成长后就可以喂给牛吃了。每头小牛吃过5次草之后就会长大了。要求使用多线程来完成。小牛(消费者)线程和草(生产者)之间需要通信。
以下是我的代码:

import threading
import random
from time import sleep

"""
声明全局变量:
num_cows:       牛的数量,   整形,十头。
cows:           牛的集合,   列表(数组)。 长度:10
num_grass:      草的数量,   整形,若干。  区间:50-101棵。  为了确保每头牛都可以长大,小草必须至少有50棵。
grass:          草的集合,   列表(数组)。 长度:num_grass
initial_stat:   草/牛的初始状态,整形,设置为0。
increment:      用于改变状态的变量,整形,设置为0。
"""
# 定义全局变量
num_cows, initial_stat, num_grass = 10, \
                                    0, \
                                    random.randint(50, 101)
cows, grass = [], []

for i in range(num_grass):  # 设置草儿数量,初始化每一棵小草状态
    grass.append(initial_stat)

for i in range(num_cows):  # 初始化每一头牛
    cows.append(initial_stat)


# TODO 草儿生长类
class GrassGrow(threading.Thread):
    """草成长线程"""

    # TODO 重写run函数
    def run(self):
        global grass
        global cows
        while True:
            ct.acquire()
            print("一天过去了...小草会不会生长呢?")
            grass = rain(grass)  # 淋雨的草儿成长一次,数位进一, 呼叫rain函数, 传入参数grass列表
            if len(grass) > 0:  # 判断还有没有需要生长的草儿
                if grassgrow(grass):  # 检查草儿,若有一株淋到三次雨,通知牛儿吃草
                    print("提醒牛儿该吃草了")
                    ct.notify()  # 提醒牛儿线程该吃草了
                    ct.release()
                    print("草线程解锁")
                    sleep(1)
                    print("通知牛儿吃草了")
            elif len(grass) <= 0:  # 如果草儿被吃完了,结束进程
                print("草儿被吃光啦")
                ct.release()  # 解锁
                break  # 退出程序


# TODO 牛儿生长类
class CowGrow(threading.Thread):
    """牛儿成长线程"""
    print("start")

    # TODO 重写run函数
    def run(self):
        print("1")
        global cows
        global grass
        # TODO 随机一头牛吃草
        while True:
            print("2")
            ct.acquire()
            print("3")
            ct.wait()
            print("4")
            if grassgrow(grass) and 5 not in cows:
                print("牛有草能吃了")
                # 长大的小草中,随机吃掉一株,从草儿列表中移除
                index = []
                for i in range(len(grass)):
                    if grass[i] >= 3:
                        index.append(i)
                delete = index[random.randint(0, len(index) - 1)]
                del grass[delete]
                cows[random.randint(range(len(cows)))] += 1  # 随机一头牛吃草,状态进1
                print("有一头牛把吃了一颗草,现在的牛儿们是:{}".format(cows))

            # 判断牛儿中是否有长大的牛儿
            elif 5 in cows:
                # 移除所有已经长大的牛儿
                for cow in range(len(cows)):
                    if cows[cow] == 5:
                        del cows[cow]
            # 判断是不是所有的牛儿都长大了,如果都长大了,结束进程
            elif len(cows) == 0:
                print("所有的牛儿都长大啦")
                ct.release()
                break
            ct.wait()
            ct.release()
            # sleep(1)


# TODO 下雨函数
def rain(grass_list):
    """

    :param grass_list:  接收  草儿列表作为参数
    :return:            返回  新的,淋雨之后的草儿列表
    """
    # 遍历草列表中的每一株草
    rain_probability = random.randint(1, 101)
    # 每天有20%几率局部下雨。如果未下雨,则所有小草都不会成长。如果下雨了,局部小草会成长。
    if rain_probability <= 20:
        for a_grass in range(len(grass_list)):
            grass_grow_prob = random.randint(1, 101)
            if grass_grow_prob <= 50 and 0 <= grass_list[a_grass] <= 2:
                grass_list[a_grass] += 1
        print("今天下雨啦,现在的小草们:{}".format(grass))
    print("今天没有下雨,没有小草生长...")
    return grass_list


# TODO 判断草长大函数
def grassgrow(grass_list):
    """

    :param grass_list:  接收  草儿列表作为参数
    :return:            返回  若有生长好的小草则返回真,否则为假
    """
    if 3 not in grass_list:
        print("目前为止还没有小草生长完成")
        return False
    else:
        print("有小草生长完成了,现在的小草们:{}".format(grass))
        return True


if __name__ == "__main__":
    ct = threading.Condition()  # 定义线程变量, 用于多线程通信
    cow_thread = CowGrow()
    grass_thread = GrassGrow()
    cow_thread.start()
    print("牛等待吃草")
    grass_thread.start()

rain函数用来20%几率下雨, grasgrow函数用来判断有没有草淋了三次雨, 一旦有草淋到三次雨就可以了通知CowGrow线程吃草了。

我的解题思路是: 创建一个列表grass代表草, 一个列表cows代表牛。类GrassGrow中当判断grassgrow函数为真时, 唤醒牛线程。然后随机一头牛吃了一颗草之后,阻塞自己等待。而当我实际运行的时候,牛在一开始被阻塞之后一直没有被唤醒

以下是运行结果:

start
1
2
3牛等待吃草

一天过去了...小草会不会生长呢?
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1]
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[1, 1, 1, 0, 0, 2, 1, 1, 1, 2, 0, 0, 1, 1, 2, 1, 2, 2, 1, 0, 1, 1, 0, 1, 2, 1, 0, 2, 1, 1, 0, 1, 2, 1, 1, 0, 1, 0, 2, 1, 2, 2, 2, 0, 0, 2, 1, 2, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 0, 1, 1, 2, 2, 2, 0, 2, 1, 2, 1, 2, 1, 0, 1, 0, 2, 1, 1, 1, 2, 1, 1, 1]
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 0, 1, 1, 2, 2, 2, 3, 2, 1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 2, 0, 1, 3, 1, 2, 0, 1, 0, 3, 2, 3, 3, 3, 0, 1, 2, 1, 2, 0, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 2, 3, 1, 2, 2, 1, 3, 2, 1, 1, 2, 3, 2, 2, 1, 2, 1, 3, 1, 2, 2, 1, 1, 0, 3, 2, 2, 1, 3, 2, 2, 1]
今天没有下雨,没有小草生长...
有小草生长完成了,现在的小草们:[2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 0, 1, 1, 2, 2, 2, 3, 2, 1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 2, 0, 1, 3, 1, 2, 0, 1, 0, 3, 2, 3, 3, 3, 0, 1, 2, 1, 2, 0, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 2, 3, 1, 2, 2, 1, 3, 2, 1, 1, 2, 3, 2, 2, 1, 2, 1, 3, 1, 2, 2, 1, 1, 0, 3, 2, 2, 1, 3, 2, 2, 1]
提醒牛儿该吃草了
草线程解锁
通知牛儿吃草了
一天过去了...小草会不会生长呢?

可以看到牛只有一开始调用了一次...之后再也没有被唤醒, 而且前几次小草没有sleep就运行了好多次,之后才开始运行sleep,打印"提醒牛儿该吃草了", "草线程解锁", "通知牛儿吃草了"才开始运行。谷歌和本站都查了一些问题,但和我的情况都不太相似。真心像各位请教...拜托了..

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2022-09-09 18:31
    关注
    不知道你这个问题是否已经解决, 如果还没有解决的话:

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 以帮助更多的人 ^-^
    评论

报告相同问题?

悬赏问题

  • ¥15 虚拟机打包apk出现错误
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么