Python调用C库的线程则比lua好多了,只是lua的体量比较小,python就要大一点,python使用ctypes调用C库(注意这里就不同于lua需要以lua形式 提供c接口,python可以直接调用C形式的函数接口了并不需要引入python形式的C),第二这里使用multiprocessing进程的方式来调用Cdll中的线程,虽然使用threading也可以完成任务,但是后者消耗的Cpu达到9%满单核运行了,而进程则没有。

1、ctypes调用Cdll库


python代码

from ctypes import *if __name__ == '__main__':pDll = CDLL("./pythonTestCDll.dll")pDll.PrintCdll()

C代码

.h文件
extern "C" __declspec(dllexport) void PrintCdll();
.cpp文件
//extern "C" __declspec(dllexport) void PrintCdll(); 这样暴露接口
void PrintCdll()
{cout << "C DLL cout :" << endl;
}

2、python中以_thread方式调用Cdll启动其中线程


python代码

from ctypes import *
import _thread
import time#以线程的方式启动Cdll
pDll = CDLL("./pythonTestCDll.dll") #加载Cdll库
pDll1 = CDLL("./pythonTestCDll.dll")
def print_time(threadName, delay):count = 0while 1:time.sleep(delay)count += 1print("%s: %s" % (threadName, time.ctime(time.time())))def testDLL( threadName, delay):pDll.startC() #调用Cdll中的函数def testDLL1( threadName, delay):pDll1.startC()if __name__ == '__main__':_thread.start_new_thread(print_time,("Thread-1", 1,))_thread.start_new_thread(testDLL, ("Thread-2", 1,))_thread.start_new_thread(testDLL1, ("Thread-3", 1,))print("start thread")#线程这样需保证主进程一直运行,如果去掉while则cdll的线程调用也会死亡while 1:pass

C代码

.h文件
extern "C" __declspec(dllexport) void startC();
.cpp文件
#include "pythonTestCDll.h"
#include <iostream>
#include <thread>
#include <string>
using namespace std;thread *th = NULL;void func()
{int num = 0;while (true){cout << "startC num :" << num++ << " flag = " << flag << endl;_sleep(1000);if (flag == 1){num = 0;}int re = 1 / num;}return;
}void startC()
{th = new thread(func);/*while (1){_sleep(10000);}*/return;
}

3、python以multiprocessing进程方式运行CDLL中的线程

从而最后可以从任务管理器中查看到每个c线程都是一个进程相当于一个exe在跑。

python代码

import multiprocessing
from multiprocessing import Process,Queue
import os
from ctypes import *
import timepDll = CDLL("./pythonTestCDll.dll")
pDll_1 = CDLL("./pythonTestCDll.dll")def testDLL():pDll.startC()while 1:time.sleep(1)print("testDLL:")def testDLL_1():pDll_1.startC()#得保证调用Cdll线程的子进程存在while死循环不然Cdll线程也会死亡while 1:time.sleep(1)print("testDLL_1:")if __name__ == '__main__':p = multiprocessing.Process(target=testDLL, args=())p.start()p = multiprocessing.Process(target=testDLL_1, args=())p.start()#使用进程的方式 则主进程没有一直运行也没有关系#while 1:#   time.sleep(1)#   print("__name__:")

C代码

.h文件
extern "C" __declspec(dllexport) void startC();
.cpp文件
#include "pythonTestCDll.h"
#include <iostream>
#include <thread>
#include <string>
using namespace std;thread *th = NULL;void func()
{int num = 0;while (true){cout << "startC num :" << num++ << " flag = " << flag << endl;_sleep(1000);if (flag == 1){num = 0;}int re = 1 / num;}return;
}void startC()
{th = new thread(func);/*while (1){_sleep(10000);}*/return;
}

4、python主进程通过multiprocessing.Queue()队列向子进程传递值从而改变Cdll的执行逻辑


python代码

import multiprocessing
from multiprocessing import Process,Queue
import os
from ctypes import *
import time
pDll = CDLL("./pythonTestCDll.dll")
pDll_1 = CDLL("./pythonTestCDll.dll")
flag = 0
def testDLL(qR, qS):pDll.startC()while 1:time.sleep(1)# 注意队列get是阻塞的,因此要先判断队列是否有值防止堵塞while qR.qsize():v = qR.get()print("testDLL:qR.size() > 0")if v == 1:print("testDLL:qR.get() %i" % v)pDll.SetFlagValue(1)else:print("testDLL:qR.get() %i" % v)qS.put("testDLL")def testDLL_1(qR, qS):pDll_1.startC()while 1:time.sleep(1)#注意队列get是阻塞的,因此要先判断队列是否有值防止堵塞#操作逻辑是如果是进程testDLL_1 取到队列值为1则不进行处理并放回队列,队列是线程安全的while qR.qsize():print("testDLL_1:qR.size() > 0")v = qR.get()if v == 1:print("testDLL_1:qR.get() %i" % v)qR.put(v)breakelse:print("testDLL_1:qR.get() %i" % v)qS.put("testDLL_1")if __name__ == '__main__':ProcessJob = []qGet = multiprocessing.Queue()  #队列是线程进程安全的无需加锁qSen = multiprocessing.Queue()p = multiprocessing.Process(target=testDLL_1, args=(qGet,qSen,))ProcessJob.append(p)p.start()  # 启动进程#p.join()  # 阻塞进程直至 当前进程中的任务完成p1 = multiprocessing.Process(target=testDLL, args=(qGet,qSen,))ProcessJob.append(p1)p1.start()  # 启动进程#p1.join()  # 阻塞进程直至 当前进程中的任务完成count = 0while 1:qGet.put(10)    #往Get队列中放值10count += 1while qSen.qsize():     #每次取值应该都取完str = qSen.get()  # 从Sen队列中取值,是那两个线程放入的print("qSen : %s" % str)# 往Get队列中放值1,在testDLL进程中接收到1会设置CDLL的flag值从而改变线程执行,而testDLL1接收1则不做处理又再将1放入进去if count == 10:qGet.put(1)time.sleep(1)

C++代码

.h文件
extern "C" __declspec(dllexport) void startC();
extern "C" __declspec(dllexport) void SetFlagValue(int v);
.cpp文件
#include "pythonTestCDll.h"
#include <iostream>
#include <thread>
#include <string>
using namespace std;thread *th = NULL;void func()
{int num = 0;while (true){cout << "startC num :" << num++ << " flag = " << flag << endl;_sleep(1000);if (flag == 1) //如果flag为1了那么就将num设置为0{num = 0;}//int re = 1 / num;}return;
}void startC()
{th = new thread(func);/*while (1){_sleep(10000);}*/return;
}void SetFlagValue(int v)
{cout << "SetFlagValue flag : " << flag << "v = "<< v << endl;flag = v;cout << "SetFlagValue flag :  " << flag << endl;
}

5、以类多个文件的管理形式实现进程multiprocessing方式的

from DllClass import MyClass 即可导入DllClass 文件中的MyClass

python代码

DllClass.py文件
class MyClass:#成员变量name = ''id = 0state = 0pDll = 0# 构造函数def __init__(self, name, id, state):self.name = nameself.id = idself.state = state#成员方法def getState(self):return self.statedef pocD(self, name):return-----------------------------------------DllScoketClass.py文件
from ctypes import *import time
from multiprocessing import Queue
from DllClass import MyClassclass DllScoketClass(MyClass):soc = ''def __init__(self, soc, name, id, state):super(DllScoketClass, self).__init__(name, id, state)       #需显示调用父类__init__构造函数self.soc = socdef pocD(self, qR, qS):pDll = CDLL("./pythonTestCDll.dll")pDll.startC() #启动Cdll的线程#处理逻辑while 1:time.sleep(1)#接收守护进程中对队列传递的参数if qR.qsize() > 0:v = qR.get()print("DllScoketClass:qR.size() > 0")if v == 1:pDll.SetFlagValue(1) #调用CDLL的函数改变其中流程else:print("DllScoketClass:qR.size() < 0")qS.put("DllScoketClass")end--------------------------------------------------
main.py文件
import os
import time
import multiprocessing
from DllScoketClass import DllScoketClass #从DllClass.py中导入MyClass类if __name__ == '__main__':c1 = DllScoketClass("soc", "c1", 0, 0)c2 = DllScoketClass("soc2", "c2", 0, 0)print("父类方法: %i" % c1.getState())ProcessJob = []qGet = multiprocessing.Queue()qSen = multiprocessing.Queue()p = multiprocessing.Process(target=c1.pocD, args=(qGet, qSen, ))ProcessJob.append(p)p.start()  # 启动进程p = multiprocessing.Process(target=c2.pocD, args=(qGet, qSen,))ProcessJob.append(p)p.start()  # 启动进程count = 0while 1:if qSen.qsize() > 0:    #防止get阻塞进程str = qSen.get()print("qSen : %s" % str)if count == 10:qGet.put(1)count += 1time.sleep(1)end

C++代码与上节一致

6、如Cdll崩溃需由multiprocessing再次调起

如果Cdll崩溃那么其实调用Cdll的子进程的状态也是死亡了那么就可以根据判断子进程的状态判断是否奔溃,从而进行再次调起子进程从而再次调起Cdll线程。
python代码,只有main.py代码的main函数的while中多出判断子进程状态并如果有死亡子进程则重新调起

main.py文件
# This is a sample Python script.import os
import time
import multiprocessing
from DllScoketClass import DllScoketClass #从DllClass.py中导入MyClass类if __name__ == '__main__':c1 = DllScoketClass("soc", "c1", 0, 0)c2 = DllScoketClass("soc2", "c2", 0, 0)print("父类方法: %i" % c1.getState())ProcessJob = []qGet = multiprocessing.Queue()qSen = multiprocessing.Queue()p = multiprocessing.Process(target=c1.pocD, args=(qGet, qSen, ))ProcessJob.append(p)p.start()  # 启动进程p = multiprocessing.Process(target=c2.pocD, args=(qGet, qSen,))ProcessJob.append(p)p.start()  # 启动进程count = 0while 1:if qSen.qsize() > 0:    #防止get阻塞进程str = qSen.get()print("qSen : %s" % str)if count == 10:qGet.put(1)count += 1time.sleep(1)nums = 0while nums < len(ProcessJob):       #循环遍历所有子进程判断其状态,如果死亡则重新调起if ProcessJob[nums].is_alive() == False:  # 如果进程状态死亡那么则重新启动ProcessJob[nums].terminate()    #杀死进程ProcessJob[nums].join(0.1)      #回收print(ProcessJob)ProcessJob.remove(ProcessJob[nums])print(ProcessJob)p = multiprocessing.Process(target=c1.pocD, args=(qGet, qSen,))     #重新创建count = 0ProcessJob.append(p)p.start()       #调起print(ProcessJob)nums+=1end

7、在Cdll和python中传入传出字符串使用ctypes


python代码

import multiprocessing
from multiprocessing import Process,Queue
import os
from ctypes import *
import timepDll = CDLL("./pythonTestCDll.dll")def testDLL():pstr = create_string_buffer(1024,  '\0')    # 创建字符串缓冲区# 对输入输出参数进行声明GetAndSetString = pDll.GetAndSetStringGetAndSetString.restype = c_char_pGetAndSetString.argtypes = [c_char_p]pchar = GetAndSetString(pstr)szbuffer = c_char_p(pchar)  # 强制转换为c_char_p类型,取其value值print(pstr.value)print(szbuffer.value)if __name__ == '__main__':testDLL()

C++代码

.h文件
extern "C" __declspec(dllexport) char* GetAndSetString(char*);
.cpp文件
char* GetAndSetString(char* s)
{strcpy(s, "CDLL");char * greeting = "Cdll String";cout << "C DLL cout :" << s << endl;return greeting;
}

8、在Cdll和python相互间json字符串的相关操作

纯python内部json与python对象的转换

import json# Python 字典类型转换为 JSON 对象
data1 = {'no': 1,'name': 'Runoob','url': 'http://www.runoob.com'
}json_str = json.dumps(data1)
print("Python 原始数据:", repr(data1))
print("JSON 对象:", json_str)# 将 JSON 对象转换为 Python 字典
data2 = json.loads(json_str)
print("data2['name']: ", data2['name'])
print("data2['url']: ", data2['url'])


python代码

from ctypes import *
import time
import json#在Cdll和python中实现字符串传替
if __name__ == '__main__':pDll = CDLL("./pythonTestCDll.dll") #加载dll库data1 = {'no': 1,'name': 'Runoob','url': 'http://www.runoob.com'}data1['id'] = 12312 #添加一组元素json_str = json.dumps(data1)    #将python对象转换为json字符串传递到C端pstr = create_string_buffer(bytes(json_str, encoding='utf8'))  # 创建字符串缓冲区#对输入输出参数进行声明GetJson = pDll.GetJsonGetJson.restype = c_char_pGetJson.argtypes = [c_char_p]pchar = GetJson(pstr)szbuffer = c_char_p(pchar)#强制转换为c_char_p类型,取其value值print(pstr.value)print(szbuffer.value)data2 = json.loads(szbuffer.value) #将Cdll返回的json格式字符串进行转换为python对象print("data2['name']: ", data2['name'])print("data2['no']: ", data2['no'])print("data2['url']: ", data2['url'])

C++代码
需引入json的第三方库,配置头文件和lib文件即可

.h文件
extern "C" __declspec(dllexport) char* GetJson(const char *s);
.cpp文件
#include "pythonTestCDll.h"
#include <iostream>
#include <thread>
#include <string>
#include "json/json.h"
using namespace std;
char * GetJson(const char *s)
{//char* greeting = (char*)malloc(100);//strcpy(s, "afadsfads");char * greeting =  "{\"no\": 1, \"name\": \"Runoob\", \"url\": \"http://www.runoob.com\"}";cout <<  "C DLL cout :"<< s << endl;Json::Reader reader;Json::Value root;if (reader.parse(s, root))  // reader将Json字符串解析到root,root将包含Json里所有子元素  {std::string upload_id = root["name"].asString();  // 访问节点,int code = root["no"].asInt();    // 访问节点,cout << "CDLL cout root[name]:" << upload_id << endl;cout << "CDLL cout root[no]:" << code << endl;}return greeting;
}

9、python打包exe,注意multiprocessing打包的坑

打包命令

pip3 install pyinstaller
pyinstaller -F main.py DllClass.py DllScoketClass.py
如果有第三方库需放置exe目录才能运行

需要在main函数后调用这个才能打包exe后运行成功
if __name__ == '__main__':multiprocessing.freeze_support()    #在windows上pyinstaller打包多进程程序需要添加特殊指令

参考博客

https://www.runoob.com/python3/python3-function.html 基础知识
https://blog.csdn.net/cym1990/article/details/72583672 VS2015用C++创建动态库DLL及使用
https://www.cnblogs.com/wqpkita/p/7124930.html python 如何在一个.py文件中调用另一个.py文件的类
https://www.cnblogs.com/FMS-Shaw/p/9751838.html python多进程multiprocessing
https://www.cnblogs.com/eailoo/p/9178763.html multiprocessing的生产者消费者模型
https://docs.python.org/2/library/multiprocessing.html multiprocessing python官网文档
https://www.cnblogs.com/FHC1994/p/11421229.html Python调用DLL动态链接库——ctypes使用
https://blog.csdn.net/leishupei/article/details/114923207 进程终止及进程状态
https://www.cnpython.com/qa/56334 ctypes从c函数返回字符串
https://baijiahao.baidu.com/s?id=1615259691934668555&wfr=spider&for=pc 如何调用DLL函数之传递数值、指针与字符串参数
https://blog.csdn.net/cainiao_python/article/details/108543978 Python打包成exe
https://blog.csdn.net/lghello/article/details/105824910 Pyinstaller打包python多进程程序出错 出现多个窗口

Python调用C库及进程形式启动C的线程相关推荐

  1. PSCAD通过python调用自动化库的实现

    带有python脚本的pscad自动化 PSCAD通过python调用自动化库的实现 前期准备 实现 导入项目 官方例子 PSCAD通过python调用自动化库的实现 在网上搜了一圈没有找到,通过油管 ...

  2. python 调用 so 库 需要注意的地方

    2019独角兽企业重金招聘Python工程师标准>>> 使用C++而不是C来编写so库时往往会遇到一些问题,这里着重探讨一下linux环境下C++编写so库 及python调用so库 ...

  3. python调用js库中的函数_Python 调用JS文件中的函数

    Python 调用JS文件中的函数 1.安装PyExecJS第三方库 2.导入库:import execjs 3.调用JS文件中的方法 Passwd = execjs.compile(open(r&q ...

  4. python调用 matlab库_python调用matlab的搜索结果-阿里云开发者社区

    2018python技术问答集锦,希望能给喜欢python的同学一些帮助 小编发现问答专区中有很多人在问关于python的问题,小编把这些问题汇总一下,希望能给喜欢python的大家一些启示和帮助 本 ...

  5. python 调用c++库接口出错

    首先,python使用c++库传数据的部分方法在我之前的小心得里有:python调用c++的库传递二级指针,希望有帮到大家. 今天说一下c++的接口里使用智能指针shared_ptr接收数据的问题,接 ...

  6. python dll 调用 方法未找到_大牛经验分享之谈:Python调用.NET库的方法步骤(建议收藏)...

    开发背景是这样的:整个项目中使用很多台摩托罗拉的RFID读卡器,我要为这些读卡器写一个管理程序,判断是否有RFID标签进入或离开某个区域.用户提供给我的,除了设备,就是一个.net的动态库文件. 经朋 ...

  7. python调用数学库_python 数学库

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我正在寻找一个3d数学库在python或python绑定. 它需要处理旋转,平移 ...

  8. 数据可视化:python调用pyecharts库绘制航线专题图

    写在前面 这学期上了数据通讯这门课,其中有一个作业是要求爬取某一天各重要城市到上海虹桥以及上海浦东两机场的航班信息,然后进行可视化.数据分析.在这一份作业用到的可视化工具是python的pyechar ...

  9. python加载动态库_使用Python调用动态库

    我个人在日常使用电脑时,经常需要使用Google,于是就要切换代理,基本上是一会儿切换为代理,一会儿切换成直连,老是打开internet 选项去设置,很不方便,于是我萌生了一个想法: 做一个开关,我想 ...

最新文章

  1. Computer Vision Tasks
  2. LeetCode刷题记录6——696. Count Binary Substrings(easy)
  3. Delphi真的没落了吗?_说Delphi母语Pascal的另一个应用
  4. zxing 源码笔记
  5. 一起学nRF51xx 8 -  Time
  6. 从零搭建Prometheus监控报警系统
  7. Linux多线程开发-线程同步-条件变量pthread_cond_t
  8. 【C语言进阶深度学习记录】十三 C语言中 ++和--操作符
  9. cygwin 编译linux内核,【记录】Cygwin下交叉编译Linux内核时用make menuconfig去确认和修改配置...
  10. 【转】linux内核态和用户态的区别
  11. java计算两点距离_Java 使用经度计算两点之间的距离?
  12. PHP沉思录之三:Smarty
  13. OrthoMCL Pipeline 安装
  14. mysql var和varp的区别_var方差(var和方差的区别)
  15. matlab受力分析,基于Matlab的多支座蒸压釜的受力分析和强度计算
  16. 因为高考是最相对公平的一次竞争和选拔
  17. [EventKit] Error getting default calendar for new reminders: Error Domain=EKCADErrorDomain Code=1013
  18. 蒂森MC2_B系统调试软件 蒂森MC2_B系统调试软件
  19. 游戏对战平台搭建要选什么服务器
  20. Linus Torvalds的最新电脑配置

热门文章

  1. 通天阁塔机器人图片_世界最大双足机器人亮相世博大阪馆
  2. R语言绘制社会网络图
  3. 使用freemarker导出excel不兼容2007问题
  4. QQ自动抢红包脚本源码,没什么卵用.基于autojs的无障碍免root
  5. 西门子PLC S7-200cn和S7-200 smart 设备锁机程序 ,有动态验证码,无限次加密
  6. 军犬舆情每日热点:支付宝用户超10亿;145名婴幼儿口服过期疫苗
  7. ICS Protocol Dissection
  8. 变换树根(树的遍历)
  9. 万年历首页效果android,简约好用的日历APP
  10. ubuntu20.04安装rxt3090驱动步骤和遇到的问题