本文可以获取信息:
- python和c混合编程
- python如何向dll中传入结构体数组
- 本设计语言采用python3、c,工具采用pycharm、dev c++
最近小狼在研究关于作业调度的一个设计
调度方面,使用c语言肯定是足以实现这个要求的,虽然界面…好吧,那就没有界面。小狼正好了解一丢丢python知识,于是想着能不能python写个界面,然后把数据给c处理呢?索性借此学习一下关于python和c的混合编程。
所以,小狼的思路如下:
- 首先使用c语言写出关于设计的计算部分,提供函数计算处理数据
- 使用python编写窗口界面,这里需要用到python自带的tkinter库(python还有其他主流的GUI库有WxPython和PyQt库,大家可以自行了解)。
- 将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()
过程中关键部分:
- 分别在python文件和c文件中建立对应的结构体
- python中实现读取GUI中读取输入框信息,以及在窗口显示信息
- 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也能行,但有没有办法在程序运行过程中根据需求,去扩大我的内存量呢?)