cpp-thread

同步

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.