windows build

环境需求

  1. python 2.x
  2. git
  3. vs2019

源代码

先下载相关代码

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
git clone https://skia.googlesource.com/skia.git
进入 skia 的源码目录
cd skia
python tools/git-sync-deps
  1. 工具添加到环境变量中

set PATH=%PATH%;E:\project\cpp\skia_project\depot_tools
set PATH=%PATH%;E:\project\cpp\skia_project\skia\bin\

查看 ninja 是否存在。命令行输入 ninja 查看是否成功

下面是失败的信息

"ninja" 不是内部或外部命令,也不是可运行的程序或批处理文件。

命令行输入 gn 查看是否成功

"gn" 不是内部或外部命令,也不是可运行的程序或批处理文件。 则是配置失败

配置 VC 目录

打开 skia/gn/BUILDCONFIG.gn 文件

win_vc = “” 的值设置为 Visual Studio 的安装目录下的VC目录
配置 SDK 目录 win_sdk = "D:/Windows Kits/10"

只有 VC 可以编译 32 位的
This toolchain is the only way we support 32-bit builds, by also setting target_cpu="x86"

官方强烈推荐使用 clang-cl 构建,高度优化

clang_win = "C:\Program Files\LLVM"

Run GN to generate your build files.

## 直接构建VisualStudio的.sln文件
gn gen out/sln --ide=vs

静态 debug
gn gen out/Clang --args="cxx=\"clang++\" cc=\"clang\" is_debug=true"

静态 release
gn gen out/Clang_release --args="cxx=\"clang++\" cc=\"clang\" is_debug=false"



bin/gn gen out/Shared --args='is_official_build=true is_component_build=true'
--ide=vs
bin\gn gen out/Static_x86 --args="clang_win=\"C:\Program Files\LLVM\" target_cpu=\"x86\" is_debug=false is_official_build=true skia_use_system_expat=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false"


bin/gn gen out/Debug
bin/gn gen out/Release --args='is_debug=false'
bin/gn gen out/Clang --args='cc="clang" cxx="clang++"'
bin/gn gen out/Cached --args='cc_wrapper="ccache"'
bin/gn gen out/RTTI --args='extra_cflags_cc=["-frtti"]'

is_official_build=true 优化编译
is_official_build=false debug 编译

编译

ninja -C out/Static
ninja -C out/Shared
ninja -C out/Debug
ninja -C out/Release
ninja -C out/Clang
ninja -C out/Clang_release
ninja -C out/Cached
ninja -C out/RTTI

有更新时,重新 build

git pull
python tools/git-sync-deps
ninja -C out/Static

协议:pack://
一种用于访问编译时已经知道的文件,用application:///
一种用于访问编译时不知道、运行时才知道的文件,用siteoforigin:///

一般用逗号代替斜杠,也就是改写作application:,,,

用XAML引用资源

<Window.Resources>
<BitmapImage x:Key="img_black" UriSource="img/black-48.png" DecodePixelWidth="48" />
<BitmapImage x:Key="img_green" UriSource="img/green-48.png" DecodePixelWidth="48" />
<BitmapImage x:Key="img_red" UriSource="img/red-48.png" DecodePixelWidth="24" />
<BitmapImage x:Key="img_black24" UriSource="img/black-48.png" DecodePixelWidth="24" />
</Window.Resources>

<Grid.Background>
<ImageBrush ImageSource="pack://application:,,,/watermark.png" />
</Grid.Background>

用代码引用资源

Image img;
img.Source=new BitmapImage(new Uri("pack://application:,,,/images/my.jpg"),UriKind.Relative);

防止回车,ESC退出

BOOL CMRLGaugerDrawerDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
{
// Do not process further
return TRUE;
}
}

return CDialogEx::PreTranslateMessage(pMsg);
}

设置标题文字

#define APP_VERSION ("serial port tool version: 2020.02.19-1341")

BOOL CcomToolsDlg::OnInitDialog()
{
this->SetWindowText(s2w(APP_VERSION).c_str());
...
}

问题对话框

if (IDYES == AfxMessageBox(L"即将删除所有标记的测量点,请再次确认该操作。",MB_YESNO))
{
// do something
}

添加菜单

添加资源,创建菜单
对话框属性里面找到 menu 然后选择已创建的菜单ID就可以了

防止回车,ESC退出

BOOL CMRLGaugerDrawerDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
{
// Do not process further
return TRUE;
}
}

return CDialogEx::PreTranslateMessage(pMsg);
}

设置标题文字

#define APP_VERSION ("serial port tool version: 2020.02.19-1341")

BOOL CcomToolsDlg::OnInitDialog()
{
this->SetWindowText(s2w(APP_VERSION).c_str());
...
}

问题对话框

if (IDYES == AfxMessageBox(L"即将删除所有标记的测量点,请再次确认该操作。",MB_YESNO))
{
// do something
}

添加菜单

添加资源,创建菜单
对话框属性里面找到 menu 然后选择已创建的菜单ID就可以了

同步

c++11
lock_guard is no longer recommended.

c++ 17
unique_lock and scoped_lock are recommended.

unique_lock 和 lock_guard 类似,增加一些有用的函数。
unique_lock can unlock, not lock_guard

// 发送队列锁
std::mutex m_mutex_write;
std::unique_lock guard(m_mutex_write);
// 可以在 guard 生命周期结束前解锁
guard.unlock();
// 解锁后还可以再次加锁
guard.lock();

wait event

win32

Condition Variables

临界区本身不是内核对象,它是工作在用户态的,所以速度快一些
互斥量、信号量、事件都是Windows的内核对象,当程序对这些对象进行控制时会自动转换到核心态。

C++ 方式

/// 实例容器锁
mutable std::mutex mutMapInst;

{
std::lock_guard<std::mutex>lk(m_devInfo.mutMapInst);
m_devInfo.mapInst.emplace(make_pair(instId, &dev));
}

MFC 方式

CMutex Mutex;

CSingleLock SingleLock(&Mutex);
SingleLock.Lock();

Win32 方式

CRITICAL_SECTION cs;

InitializeCriticalSection(&m_curInfo.cs);

EnterCriticalSection(&m_curInfo.cs);
m_curInfo.timeCmp = time(NULL);
LeaveCriticalSection(&m_curInfo.cs);

DeleteCriticalSection(&m_curInfo.cs);

同步事件

// 同步发送数据的,读取完毕后,在发送
HANDLE m_hEvent_write;

m_hEvent_write = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);

WaitForSingleObject(pwnd->m_hEvent_write, INFINITE);
// go on
::SetEvent(m_hEvent_write);

CloseHandle(m_hEvent_write)

指针参数

可以使用智能指针保存参数,然后传给工作线程。
目前还没找到更好的办法,只能复制一份给工作线程使用。

int CserialPort::write(const BYTE* data, const DWORD& length)
{
std::shared_ptr<BYTE[]> spBuf(new BYTE[length]);
memcpy(spBuf.get(), data, length);

std::thread threadWork = std::thread(threadWrite, this, spBuf,length);
threadWork.detach();
return 0;
}

C++ 14

注意:可被 joinable 的 std::thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.

if (false == m_thread_recive.joinable())
{
m_thread_recive = std::thread(threadReceive, this);
}

int threadReceive(const void* p)
{
CTcpClient* pwnd = (CTcpClient*)p;
while (FLAG_EXIT_THREAD_RECEIVE != (pwnd->m_flag&FLAG_EXIT_THREAD_RECEIVE))
{


for (int i = 0; i < 20; ++i)
{
if (FLAG_EXIT_THREAD_RECEIVE == (pwnd->m_flag&FLAG_EXIT_THREAD_RECEIVE))
{
goto skip_return;
}
this_thread::sleep_for(chrono::milliseconds(100));
}
}
skip_return:
return 0;
}
// Create a thread using member function
std::thread th(&Task::execute, taskPtr, "Sample Task");
std::thread m_threadHttpServer;

if (FLAG_HTTP_SERVER_RUNNING != (g_iFlag&FLAG_HTTP_SERVER_RUNNING))
{
m_threadHttpServer = std::thread(threadHttpServer, (this), 2,"other param");
}

g_iFlag |= FLAG_EXIT_HTTP_SERVER;
while (FLAG_HTTP_SERVER_RUNNING == (g_iFlag&FLAG_HTTP_SERVER_RUNNING))
{
Sleep(200);
}

if (m_threadHttpServer.joinable())
{
m_threadHttpServer.join();
}
g_iFlag &= (~FLAG_EXIT_HTTP_SERVER);

ref.

A thread can be created in several ways:

  1. Using a function pointer
  2. Using a functor
  3. Using a lambda function

对于判断线程是否执行完毕,可以通过自己设置 flag 来判断.

// thread example
#include <iostream> // std::cout
#include <thread> // std::thread


str.Format(L"foo %d\n", i);
OutputDebugString(str);
Sleep(1000);
}
}

void bar(int& x, int& out)
{
int m = 0;
CString str;
for (int i = 0; i < 5; ++i)
{
m += x;
str.Format(L"bar %d\n", i);
OutputDebugString(str);
Sleep(1000);
}
out = m;
}

int main()
{
CString str;

std::thread first(foo); // spawn new thread that calls foo()
int out = 0;
int in = 10;
std::thread second(bar, ref(in),ref(out)); // spawn new thread that calls bar(0)

OutputDebugString(L"main, foo and bar now execute concurrently...\n");

// synchronize threads:
first.join(); // pauses until first finishes
second.join(); // pauses until second finishes


str.Format(L"foo and bar completed. out:%d\n", out);

OutputDebugString(str);

return 0;
}

std::ref
主要是考虑函数式编程(如std::bind)在使用时,是对参数直接拷贝,而不是引用。

warning: all parameters is passing default by value unless you wrap them in std::ref.

C run-time libraries

_beginthread or _beginthreadex

结束线程
_endthread
_endthread automatically closes the thread handle.

doc

追加文档

ui.plainTextEdit_out->appendPlainText(strRead);

2019 年过去了,这是一个特殊的年,因为非冠状流行病毒疫情,全国上下几乎都很宅。商场,饭店,电影院,各种场所都关了,直到今天,商场里面也没有几个人。

年前被动换了工作,新找的工作在奉贤,已经出了上海市区了。

2020 年我的计划是,先拿到本科毕业证,5月份答辩。
然后全力看股票,作为我下半生的养老项目。

工作上是机械测量相关的业务,对我来说难度不大。应该可以轻松应对。

以下是我在 2020 年要完成的任务

  1. 本科毕业证
  2. 重点发展股票事业
  3. 健身

msdn 串口总体描述
book: C Programmer’s Guide to Serial Communications

Nonoverlapped I/O vs Overlapped I/O
Overlapped I/O 是异步的,Nonoverlapped I/O 是同步的,
同步操作,调用线程会被阻塞,通常使用多个线程来操作,但是如果一个线程中 readFile 阻塞,那么另一个线程的 writeFile 也会被阻塞。
异步,同步接口的选择依据主要是可移植性。

Overlapped I/O
更具有灵活性和效率,允许多线程在阻塞等待时同时处理不同的I/O操作,允许单线程在阻塞时在后台执行多个请求

等待有两种方式:

  1. 等待 hEvent member of the OVERLAPPED structure 使用 WaitForSingleObject
  2. wait for the call to the GetOverlappedResult function

Serial Status

两种方式:

  1. 使用事件 mask
  2. 使用 polling (低效,不推荐)
阅读全文 »

使用 qt designer 创建信号槽关联。

或者使用代码关联

// Connect button signal to appropriate slot
connect(m_button, SIGNAL (released()), this, SLOT (handleButton()));

public slots:
void onBtn_driver_config();

void QtGuiApplication1::onBtn_driver_config()
{
QMessageBox::information(NULL, "info", "onBtn_driver_config", QMessageBox::Ok);
}