python向dll传入结构体,并用tkinter制作界面实现 作业调度算法

本文可以获取信息:

  1. python和c混合编程
  2. python如何向dll中传入结构体数组
  3. 本设计语言采用python3、c,工具采用pycharm、dev c++

最近小狼在研究关于作业调度的一个设计

调度方面,使用c语言肯定是足以实现这个要求的,虽然界面…好吧,那就没有界面。小狼正好了解一丢丢python知识,于是想着能不能python写个界面,然后把数据给c处理呢?索性借此学习一下关于python和c的混合编程。

所以,小狼的思路如下:

  1. 首先使用c语言写出关于设计的计算部分,提供函数计算处理数据
  2. 使用python编写窗口界面,这里需要用到python自带的tkinter库(python还有其他主流的GUI库有WxPython和PyQt库,大家可以自行了解)。
  3. 将python窗口所获取的数据存入定义的数据结构中,然后将数据结构传入dll中,经过处理后再返回给python,然后显示

OK,大概思路就是如此

详细代码:

dll.h

#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct
{
    char task_name[10];//作业名称
    float arrive_time;//到达时间
    float run_time;//要求服务时间
    float startime;//开始时间
    float finitime;//完成时间
    float TAtime,TAWtime;//周转时间,带权周转时间
    float prio;//响应比 
}job_information;

typedef struct
{
	job_information *jcb;
	int len;
	float ave_TAtime; //平均作业周转时间
	float ave_TAWtime; //平均带权作业周转时间
}outStruct;

int __declspec(dllexport) struct_init(outStruct *o);

void __declspec(dllexport) struct_over(outStruct *o); 

void __declspec(dllexport) manage(outStruct *o);

void __declspec(dllexport) FCFS(outStruct *o); 

void __declspec(dllexport) SJF(outStruct *o); 

void __declspec(dllexport) HRRF(outStruct *o); 

#endif /* _DLL_H_ */

dllmain.c

#include "dll.h"

// 初始化,分配初始内存 
int struct_init(outStruct *o)
{
	o->jcb = (job_information *)malloc(sizeof(char)*10*o->len);
	if(o->jcb == NULL) // 判断内存分配是否成功 
	{
		return 1;
	}
	return 0; 
}

// 程序结束,释放内存 
void struct_over(outStruct *o)
{
	free(o->jcb);
	
	o->jcb = NULL; // 释放后的指针置空,防止野指针 
}

// 进行时间上的排序 
void manage(outStruct *o)
{
	int i, j;
	for(j=0;j<o->len;j++)
    {
        for(i=0;i<o->len-j;i++)
        {
            if(o->jcb[i].arrive_time>o->jcb[i+1].arrive_time)
            {
                o->jcb[o->len]=o->jcb[i];
                o->jcb[i]=o->jcb[i+1];
                o->jcb[i+1]=o->jcb[o->len];
            }
        }
    }
}

//先来先服务
void FCFS(outStruct *o)
{
    int i;
    float sum_TAtime=0;//作业总周转时间
    float sum_TAWtime=0;//作业总带权周转时间

    o->jcb[0].finitime = o->jcb[0].arrive_time + o->jcb[0].run_time;
    o->jcb[0].startime = o->jcb[0].arrive_time;
    
    for(i = 1; i < o->len; i++)
    {
        o->jcb[i].startime = o->jcb[i-1].finitime;
        o->jcb[i].finitime = o->jcb[i-1].finitime + o->jcb[i].run_time;
    }
    for(i = 0; i < o->len; i++)
    {
        o->jcb[i].TAtime = o->jcb[i].finitime - o->jcb[i].arrive_time;
        sum_TAtime += o->jcb[i].TAtime;
        o->jcb[i].TAWtime = o->jcb[i].TAtime / o->jcb[i].run_time;
        sum_TAWtime += o->jcb[i].TAWtime;
    }
    o->ave_TAtime = sum_TAtime*1.0/o->len;
    o->ave_TAWtime = sum_TAWtime*1.0/o->len;
}

//最短作业优先
void SJF(outStruct *o)
{
    int i, j;
    float sum_TAtime=0;//作业总周转时间
    float sum_TAWtime=0;//作业总带权周转时间
    
    o->jcb[0].finitime = o->jcb[0].arrive_time + o->jcb[0].run_time;
    o->jcb[0].startime = o->jcb[0].arrive_time;
    
    for(i = 1; i < o->len; i++)
    {
        for(j = 1; j <  o->len-1; j++)
        {
            if(o->jcb[j].run_time > o->jcb[j+1].run_time)
            {
                o->jcb[o->len] = o->jcb[j]; 
                o->jcb[j] = o->jcb[j+1]; 
                o->jcb[j+1] = o->jcb[o->len];
            }
        }
    }
    for(i = 1; i < o->len; i++)
    {
        o->jcb[i].startime = o->jcb[i-1].finitime;
        o->jcb[i].finitime = o->jcb[i-1].finitime + o->jcb[i].run_time;
    }
    for(i = 0; i < o->len; i++)
    {
        o->jcb[i].TAtime = o->jcb[i].finitime - o->jcb[i].arrive_time;
        sum_TAtime += o->jcb[i].TAtime;
        o->jcb[i].TAWtime = o->jcb[i].TAtime / o->jcb[i].run_time;
        sum_TAWtime += o->jcb[i].TAWtime;
    }
    o->ave_TAtime = sum_TAtime*1.0/o->len;
    o->ave_TAWtime = sum_TAWtime*1.0/o->len; 
}

//最高响应比优先
void HRRF(outStruct *o)
{
    int i, j;
    float sum_TAtime=0;//作业总周转时间
    float sum_TAWtime=0;//作业总带权周转时间
     
    o->jcb[0].finitime = o->jcb[0].arrive_time + o->jcb[0].run_time;
    o->jcb[0].startime = o->jcb[0].arrive_time;
   
    for(i = 1; i <o->len; i++)
    {
        for(j = 1; j < o->len-1; j++)
        {
            if(o->jcb[j].prio < o->jcb[j+1].prio)
            {
                if(o->jcb[j].arrive_time == o->jcb[j+1].arrive_time)
                {
                    o->jcb[o->len] = o->jcb[j]; 
                    o->jcb[j] = o->jcb[j+1]; 
                    o->jcb[j+1] = o->jcb[o->len];
                }
            }
        }
    }
    for(i = 1; i <o->len; i++)
    {
        o->jcb[i].prio = 1 + (o->jcb[i-1].finitime - o->jcb[i].arrive_time) / o->jcb[i].run_time;
        o->jcb[i].finitime = o->jcb[i-1].finitime + o->jcb[i].run_time;
    }

    for(i = 0; i <o->len; i++)
    {
        o->jcb[i].TAtime = o->jcb[i].finitime - o->jcb[i].arrive_time;
        sum_TAtime += o->jcb[i].TAtime;
        o->jcb[i].TAWtime = o->jcb[i].TAtime / o->jcb[i].run_time;
        sum_TAWtime += o->jcb[i].TAWtime;
    }
    o->ave_TAtime = sum_TAtime*1.0/o->len;
    o->ave_TAWtime = sum_TAWtime*1.0/o->len;
}

taskSchedule. py

from ctypes import *
from tkinter import *

# 定义关于作业信息的结构体
class job_information(Structure):
    _fields_ = [("name", c_char*10),
                ("arrive_time", c_float),  # 作业到达时间
                ("run_time", c_float),  # 作业所需的运行时间
                ("startime", c_float),  # 开始时间
                ("finitime", c_float),  # 完成时间
                ("TAtime", c_float),  # 周转时间
                ("TAWtime", c_float),  # 带权周转时间
                ("prio", c_float)] # 响应比

class outStruct(Structure):
    _fields_= [('jcb', POINTER(job_information)),
               ('len', c_int), # 作业数量
               ('ave_TAtime', c_float), # 平均作业周转时间
               ('ave_TAWtime', c_float)] # 平均带权作业周转时间

# 对表格中值的读取,保存和打印
def printTable():
    global i

    o.len = o.len + 1

    if i == 5:
        Label(master, text="名称").grid(row=i, column=0)
        Label(master, text="到达时刻").grid(row=i, column=1)
        Label(master, text="运行时间").grid(row=i, column=2)

    i = i + 1
    # 获取表格中值
    o.jcb[o.len-1].name = name_table.get().encode('utf-8')     # encode()将字符串转化为二进制
    o.jcb[o.len-1].arrive_time = float(arrive_time_table.get())
    o.jcb[o.len - 1].run_time = float(run_time_table.get())

    # 打印表格中值
    Label(master, text=o.jcb[o.len-1].name.decode('utf-8')).grid(row=i, column=0)      # decode()将二进制转化为字符串
    Label(master, text=o.jcb[o.len-1].arrive_time).grid(row=i, column=1)
    Label(master, text=o.jcb[o.len-1].run_time).grid(row=i, column=2)

    # 清空表格
    name_table.delete(0,'end')
    arrive_time_table.delete(0,'end')
    run_time_table.delete(0,'end')


# 对保存好的值进行计算和输出
def caculate():
    def FCFS():
        lib.manage(byref(o))
        lib.FCFS(byref(o))

        Label(print_win, text="名称").grid(row=1, column=0)
        Label(print_win, text="到达时刻").grid(row=1, column=1)
        Label(print_win, text="运行时间").grid(row=1, column=2)
        Label(print_win, text="开始时间").grid(row=1, column=3)
        Label(print_win, text="结束时间").grid(row=1, column=4)

        for i in range(o.len):
            # 打印表格中值
            Label(print_win, text=o.jcb[i].name.decode('utf-8')).grid(row=i+2, column=0)  # decode()将二进制转化为字符串
            Label(print_win, text=o.jcb[i].arrive_time).grid(row=i+2, column=1)
            Label(print_win, text=o.jcb[i].run_time).grid(row=i+2, column=2)
            Label(print_win, text=o.jcb[i].startime).grid(row=i+2, column=3)
            Label(print_win, text=o.jcb[i].finitime).grid(row=i+2, column=4)

    def SJF():
        lib.manage(byref(o))
        lib.SJF(byref(o))

        Label(print_win, text="名称").grid(row=1, column=0)
        Label(print_win, text="到达时刻").grid(row=1, column=1)
        Label(print_win, text="运行时间").grid(row=1, column=2)
        Label(print_win, text="开始时间").grid(row=1, column=3)
        Label(print_win, text="结束时间").grid(row=1, column=4)
        Label(print_win, text="周转时间").grid(row=1, column=5)
        Label(print_win, text="带权周转时间").grid(row=1, column=6)

        for i in range(o.len):
            # 打印表格中值
            Label(print_win, text=o.jcb[i].name.decode('utf-8')).grid(row=i+2, column=0)  # decode()将二进制转化为字符串
            Label(print_win, text=o.jcb[i].arrive_time).grid(row=i+2, column=1)
            Label(print_win, text=o.jcb[i].run_time).grid(row=i+2, column=2)
            Label(print_win, text=o.jcb[i].startime).grid(row=i+2, column=3)
            Label(print_win, text=o.jcb[i].finitime).grid(row=i+2, column=4)
            Label(print_win, text=o.jcb[i].finitime).grid(row=i+2, column=5)
            Label(print_win, text=o.jcb[i].finitime).grid(row=i+2, column=6)

    def HRRF():
        lib.manage(byref(o))
        lib.HRRF(byref(o))

        Label(print_win, text="名称").grid(row=1, column=0)
        Label(print_win, text="到达时刻").grid(row=1, column=1)
        Label(print_win, text="运行时间").grid(row=1, column=2)
        Label(print_win, text="开始时间").grid(row=1, column=3)
        Label(print_win, text="结束时间").grid(row=1, column=4)

    def end():
        master.destroy() # 关闭输入值窗口
        print_win.destroy() # 关闭计算窗口
        lib.struct_over(byref(o)) # 释放资源

        for i in range(o.len):
            # 打印表格中值
            Label(print_win, text=o.jcb[i].name.decode('utf-8')).grid(row=i+2, column=0)  # decode()将二进制转化为字符串
            Label(print_win, text=o.jcb[i].arrive_time).grid(row=i+2, column=1)
            Label(print_win, text=o.jcb[i].run_time).grid(row=i+2, column=2)
            Label(print_win, text=o.jcb[i].startime).grid(row=i+2, column=3)
            Label(print_win, text=o.jcb[i].finitime).grid(row=i+2, column=4)

    print_win = Tk()
    print_win.title('作业调度计算')

    Button(print_win, text="先来先服务", command=FCFS).grid(row=0, column=0, sticky=W)

    Button(print_win, text="最短作业优先", command=SJF).grid(row=0, column=1, sticky=E)

    Button(print_win, text="最高响应比优先", command=HRRF).grid(row=0, column=2, sticky=E)

    Button(print_win, text="结束", command=end).grid(row=0, column=3, sticky=E)

    print_win.mainloop()

if __name__ == "__main__":
    lib = cdll.LoadLibrary("./test_dll.dll")
    o = outStruct()

    fill = lib.struct_init(byref(o))

    if fill == 1:
        print("内存分配失败")

    o.len = 0

    master = Tk()
    master.title('单通道作业调度算法')

    global i # 控制界面输出行
    i = 5

    Label(master, text="名称:").grid(row=0)
    name_table = Entry(master)
    name_table.grid(row=0, column=1)

    Label(master, text="作业到达时刻:").grid(row=1)
    arrive_time_table = Entry(master)
    arrive_time_table.grid(row=1, column=1)

    Label(master, text="作业运行时间:").grid(row=2)
    run_time_table = Entry(master)
    run_time_table.grid(row=2, column=1)

    next = Button(master, text="下一个", command=printTable).grid(row=4, column=1, sticky=W)

    submit = Button(master, text="提交", command=caculate).grid(row=4, column=1, sticky=E)

    master.mainloop()
过程中关键部分:
  1. 分别在python文件和c文件中建立对应的结构体
  2. python中实现读取GUI中读取输入框信息,以及在窗口显示信息
  3. c中对于传入的结构体的处理(由于使用了指针,所以传入和传出值的过程就很简单了)
过程中注意问题:

c中malloc()分配内存时,一定要注意进行判断是否申请成功,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针,确保非空之后再使用函数。同样,在使用完内存块之后,我们要手动的去释放所申请内存,防止出现内存泄漏等等情况。

// 初始化,分配初始内存 
int struct_init(outStruct *o)
{
	o->jcb = (job_information *)malloc(sizeof(char)*10*o->len); 
	if(o->jcb == NULL) // 判断内存分配是否成功 
	{
		return 1;
	}
	return 0; 
}

// 程序结束,释放内存 
void struct_over(outStruct *o)
{
	free(o->jcb);
	
	o->jcb = NULL; // 释放后的指针置空,防止野指针 
}

python3中,默认编码为utf-8,对于str传给c语言时,需要使用encode()函数转为bytes,同样,c中传给python的bytes需要使用decode()函数转为str

# 获取表格中值
o.jcb[o.len-1].name = name_table.get().encode('utf-8')     # encode()将字符串转化为二进制

# 打印表格中值
Label(master, text=o.jcb[o.len-1].name.decode('utf-8')).grid(row=i, column=0)      # decode()将二进制转化为字符串
有个问题:

在程序中我在c内申请内存代码如下
o->jcb = (job_information *)malloc(sizeof(char)*10 * o->len);
我所申请的空间是依据我首次传入的o->len的大小,而在后面会出现需求内存大于申请内存的情况。这该如何解决?
(当然我直接把o->len改为个具体的实数比如400,1000也能行,但有没有办法在程序运行过程中根据需求,去扩大我的内存量呢?)

有关链接:

在这次设计过程中,小狼也是遇见了很多很多问题,查看了很多资料,部分如下:

  1. Python与C参数交互—结构体指针作为参数.
  2. Python 调用 C 动态链接库,包括结构体参数、回调函数等.
  3. 官方文档对于ctypes的解读.
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值