事件同步
事件非常有价值,它是多线程应用程序中经常使用的同步工具。在Kithara RealTime Suite中,事件是必需的,它们也必须从内核级别进行设置。普通 Windows 事件不支持内核功能。除此之外,你还可以创建Kithara事件来同步实时任务。
创建事件
注意: 在创建事件是,参数 flag 决定该事件是线程事件还是任务事件!顾名思义,线程事件只能阻塞线程,任务事件只能阻塞任务!
KS_createEvent 创建一个事件并返回一个事件句柄(这不是 Windows-Event-Handle,不得与 Windows 函数一起使用),获取的句柄是所有其他事件函数所必需的。
可以使用系统范围的唯一名称来命名事件。这样,就可以在不同的应用程序实例中使用一个事件。该名称指定给参数 name,并且必须以零结尾("\0 空终止符),最大字符串长度为 64。使用 flags 参数在普通线程事件、任务事件 (‘KSF_KERNEL_EXEC’) 和手动重置选项 (‘KSF_MANUAL_RESET’) 之间进行选择。
事件状态变更
事件的状态可以通过不同的函数进行更改。这些函数分别在手动重置事件、自动重置事件上的工作方式不同。
设置事件
函数 KS_setEvent 将设置 hEvent 中给出的事件。自动重置事件将被消耗,并从等待它的最高线程或任务自动重置。在为此事件调用 reset-function 之前,manual-reset-event 将保持设置状态。
重置事件
KS_resetEvent 将重置 manual-reset-event(如果当前已设置)。
脉冲事件
函数 KS_pulseEvent 设置并立即重置事件。可以在三种不同的情况下调用此函数(当前未设置事件):
-
没有任务/线程在等待:没有任何反应
-
一个或多个任务/线程正在等待自动重置事件:优先级最高的任务/线程将使用该事件,并且该事件将被重置。
-
一个或多个任务/线程正在等待手动重置事件:所有任务/线程都将使用该事件,然后该事件将被重置。
呼叫后将重置事件。
阻塞线程或任务
这是事件的主要功能。该事件可用于阻止线程或任务。使用“KSF_KERNEL_EXEC”创建的事件只能阻止任务,没有该标志的事件只能阻止线程。
等待事件
如果调用函数 KS_waitForEvent,则当前线程或任务将被阻止。可以通过参数 timeout 确定超时值。timeout-value 表示 100 ns 单位(与所有时间值一样)。线程或任务将被阻止,直到设置事件并可由当前线程或任务使用。当然,只有在未达到超时时。若要使用无限超时,请将参数设置为零。
查询事件状态
要读出事件的当前状态,可以调用 KS_getEventState 函数。
删除事件
要删除事件,请使用函数 KS_closeEvent。如果该事件在多个应用程序实例中使用,则必须在每个实例中关闭该事件,然后才能实际删除该事件。
项目实例
项目结构:
SharedData.h
#pragma once
#include <KrtsDemo.h>
// 内核层数据需要1字节对齐
#pragma pack(1)
typedef struct SharedData {
KSHandle event_handle; // 事件句柄
int ret; // 返回的数据
}SharedData;
#pragma pack()
KitharaDll.cpp
#include "SharedData.h"
#include <cstdint>
SharedData* sys_data_ptr_ = nullptr;
int compute;
// 初始化函数
extern "C" __declspec(dllexport) KSError __stdcall _initFunction(void* pArgs, void* pConttext) {
sys_data_ptr_ = (SharedData*)pArgs;
// 创建事件
KSError error = KS_createEvent(&sys_data_ptr_->event_handle, "DemoEvent", KSF_NO_FLAGS);
if (error != KS_OK)
{
// Todo
return error;
}
return KS_OK;
}
// 数据处理
extern "C" __declspec(dllexport) KSError __stdcall _computeEvent(void* pArgs, void* pConttext) {
compute++;
sys_data_ptr_->ret += compute;
KSError error = KS_setEvent(sys_data_ptr_->event_handle);
if (error != KS_OK)
{
// Todo
return error;
}
return KS_OK;
}
extern "C" __declspec(dllexport) KSError __stdcall _exitFunction(void* pArgs,void *pConttext) {
if (sys_data_ptr_ != nullptr)
{
KS_closeEvent(sys_data_ptr_->event_handle);
}
return KS_OK;
}
#define WIN32_LEAN_AND_MEAN
// Windows 头文件
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved) {
return TRUE;
}
KitharaDemo.cpp
#include <iostream>
#include <mutex>
#include "../KitharaDll/SharedData.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
const char customerNumber[256] = "DEMO";
SharedData* app_data_ptr_ = nullptr; // 应用层共享内存指针
SharedData* sys_data_ptr_ = nullptr; // 内核层共享内存指针
// 应用层不能使用内核层指针!!!
bool is_running_{false}; // 正在运行
KSHandle kermel_handle;
void OutputErr(KSError error, const char* pFuncName, const char* pComment)
{
if (error == KS_OK)
return;
const char* pError;
KS_getErrorString(error, &pError, KSLNG_DEFAULT);
printf("ERROR (%08X = \'%s\') - %s: %s\n", error, pError, pFuncName, pComment);
}
// 读取数据线程
KSError _stdcall ReadThread(void* pArgs)
{
if (app_data_ptr_ != nullptr)
{
KSError error;
while (is_running_)
{
error = KS_waitForEvent(app_data_ptr_->event_handle, KSF_NO_FLAGS, 0);
if (error != KS_OK)
{
return error;
}
printf("Event Read: %d \n", app_data_ptr_->ret);
}
}
return KS_OK;
}
int main()
{
KSError error;
error = KS_openDriver(customerNumber); // 所有Kithar项目的第一步
if (error != KS_OK)
{
error = 1;
OutputErr(error, "KS_openDriver", "Unable to open the driver!");
}
else
{
printf("Hello Kithara! \n");
}
// 创建共享内存
error = KS_createSharedMem(reinterpret_cast<void**>(&app_data_ptr_), reinterpret_cast<void**>(&sys_data_ptr_), "KitharaDemo", sizeof(SharedData), 0);
if (error != KS_OK)
{
OutputErr(error, "KS_createSharedMem", "failed to allocate shared memory");
KS_closeDriver();
return 0;
}
// 加载内核DLL
error = KS_loadKernel(&kermel_handle, "KitharaDll.dll",nullptr, nullptr, KSF_KERNEL_EXEC | KSF_SAVE_FPU);
if (error != KS_OK)
{
OutputErr(error, "KS_loadKernel", "load dll failed!");
KS_closeDriver();
return 0;
}
// 内核初始化
error = KS_execKernelFunction(kermel_handle, "_initFunction", sys_data_ptr_, nullptr, KSF_REALTIME_EXEC | KSF_SAVE_FPU);
if (error != KS_OK)
{
OutputErr(error, "KS_execKernelFunction", "init failed");
KS_closeDriver();
return 0;
}
// 创建线程
is_running_ = true;
app_data_ptr_->ret = 0;
error = KS_createThread(ReadThread, nullptr, nullptr);
if (error != KS_OK)
{
OutputErr(error, "KS_createThread", "create thread failed");
KS_closeDriver();
return 0;
}
// 结束线程
int time_count = 0;
while (is_running_)
{
if (++time_count > 10)
{
is_running_ = false;
}
// Todo ...
error = KS_execKernelFunction(kermel_handle, "_computeEvent", sys_data_ptr_, nullptr, KSF_REALTIME_EXEC | KSF_SAVE_FPU);
if (error != KS_OK)
{
OutputErr(error, "KS_execKernelFunction", "get compute failed");
return error;
}
Sleep(1000);
}
// 资源释放
KS_execKernelFunction(kermel_handle, "_exitFunction", sys_data_ptr_, nullptr, KSF_REALTIME_EXEC | KSF_SAVE_FPU);
// 资源内核
error = KS_freeKernel(kermel_handle);
if (error != KS_OK)
{
OutputErr(error, "KS_freeKernel", "");
KS_closeDriver();
return 0;
}
// 资源共享内存
error = KS_freeSharedMem(app_data_ptr_);
if (error != KS_OK)
{
OutputErr(error, "KS_freeSharedMem", "");
KS_closeDriver();
return 0;
}
// 关闭驱动
error = KS_closeDriver();
if (error != KS_OK)
{
OutputErr(error, "KS_closeDriver", "");
KS_closeDriver();
return 0;
}
Sleep(1000);
return 0;
}
更多实例:
smp\CanFDRecv
smp\EtherCATBridge
smp\LibraryDlibOpenCV
smp\NetworkEthernetMonitor
smp\NetworkTcpClient
smp\NetworkTcpServer
smp\CameraImageAcquisition