Thread synchronization has two aspects: locking and notification. Locking prevents access to some resource, such as a piece of shared data: that is, it enforces mutual exclusion. Notification involves passing synchronization information among cooperating threads.
//原 文说:nspr4 有两种线程同步方法,线程锁(互斥体)和通知,线程锁保护如共享区数据的一类资源. 通知通过传递同步信息来协作线程.
//线程锁(互斥体,类似与CreateMutex)有:PRLock
, ,PRMonitor
,
一.PRLock:
#include "prlock.h"
// 新建一个(初始化)Lock,返回新建的LOCK的句柄.如果没有新建成功,则返回NULL.
//在使用此lock前使用
NSPR_API(PRLock*) PR_NewLock(void);
//销毁一个Lock,在Lock不用的时候销毁它,PR_NewLock的反动作.
NSPR_API(void) PR_DestroyLock(PRLock *lock);
//使用这个Lock,类似与进入互斥一样
NSPR_API(void) PR_Lock(PRLock *lock);
NSPR_API(PRStatus) PR_Unlock(PRLock *lock);
//例程:
#include "nspr.h"
//说明上说PR_Lock是用来保护数据的,其实在这段代码中还是用来同步代码的.
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plc4.lib")
PRLock* g_lock;
void Thread_A(char* buf)
{
PR_Lock(g_lock);//进入锁(保护数据)
for (int i = 0; i != 10; i++)
{
printf("In thread A %d: %s\n", i,buf);
}
PR_Unlock(g_lock);//解锁(其它锁可以进入)
}
void Thread_B(char* buf)
{
PR_Lock(g_lock);//进入锁(保护数据)
for (int i = 0; i != 10; i++)
{
printf("In thread B %d: \n", i,buf);
}
PR_Unlock(g_lock);//解锁(其它锁可以进入)
}
int main(int argc, char* argv[])
{
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
PRThread* p_tha;
PRThread* p_thb;
g_lock = PR_NewLock(); //初始化一个锁(应处理返回NUL的情况)
p_tha = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_A,
"buffer to thread A",
PR_PRIORITY_HIGH,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
p_thb = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_B,
"buffer to thread B",
PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
PR_JoinThread(p_tha);
PR_JoinThread(p_thb);
PR_DestroyLock(g_lock);//主线程结束时锁毁这个锁
PR_Cleanup();
return 0;
}
结果
没有加LOCK时输出是这样的:
In thread A 0: buffer to thread A
In thread B 0: buffer to thread B
In thread A 1: buffer to thread A
In thread A 2: buffer to thread A
In thread B 1: buffer to thread B
In thread A 3: buffer to thread A
In thread A 4: buffer to thread A
In thread B 2: buffer to thread B
In thread A 5: buffer to thread A
In thread B 3: buffer to thread B
In thread A 6: buffer to thread A
In thread B 4: buffer to thread B
In thread A 7: buffer to thread A
In thread B 5: buffer to thread B
In thread A 8: buffer to thread A
In thread B 6: buffer to thread B
In thread A 9: buffer to thread A
In thread B 7: buffer to thread B
In thread B 8: buffer to thread B
In thread B 9: buffer to thread B
但加了Lock后就是这样了
In thread A 0: buffer to thread A
In thread A 1: buffer to thread A
In thread A 2: buffer to thread A
In thread A 3: buffer to thread A
In thread A 4: buffer to thread A
In thread A 5: buffer to thread A
In thread A 6: buffer to thread A
In thread A 7: buffer to thread A
In thread A 8: buffer to thread A
In thread A 9: buffer to thread A
In thread B 0: buffer to thread B
In thread B 1: buffer to thread B
In thread B 2: buffer to thread B
In thread B 3: buffer to thread B
In thread B 4: buffer to thread B
In thread B 5: buffer to thread B
In thread B 6: buffer to thread B
In thread B 7: buffer to thread B
In thread B 8: buffer to thread B
In thread B 9: buffer to thread B
二.PRCondVar
#include "prcvar.h
//创建一个condition varialbe(条件变量),先要创建一个Lock,用Lock来保护condition variable
//有可能返回NULL.
NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock);
//销毁一个condition variable,(当此条件变量不再用时)
NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar);
// 等待一个condition variable(条件变量),如果timeout 是PR_INTERVAL_NO_TIMEOUT则无限等待,
//如果是PR_INTERVAL_NO_WAIT好像是不再等待
//记得一定要先PR_Lock(),完成后PR_Unlock();
NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout);
//通知一个condition variable(条件变量),不管是不是已经接收到.
//记得一定要先PR_Lock(),完成后PR_Unlock();
NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar);
//类似于PR_NotifyCondVar,只是通知一组condition variable,不管是不是已经接收到.
//记得一定要先PR_Lock(),完成后PR_Unlock();
NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar);
//例程(vs2008)
#include "nspr.h"
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plc4.lib")
PRIntervalTime start_time;
PRLock* g_lock;
PRCondVar* g_condA;
PRCondVar* g_condB;
//PRMonitor* g_monitor;
void Thread_A(char* buf)
{
PR_Lock(g_lock);
for (int i = 0; i != 10; i++)
{
PR_WaitCondVar(g_condB, PR_INTERVAL_NO_TIMEOUT); //等待B通知
printf("In thread A %d: %s\n", i,buf);
PR_Sleep(1000); //A处理事件要花点时间
PR_NotifyCondVar(g_condA); //通知告诉别人说A处理完了
}
PR_Unlock(g_lock);
}
void Thread_B(char* buf)
{
PR_Lock(g_lock);
PR_NotifyCondVar(g_condB); //先通知一下,防止相互等待
for (int i = 0; i != 10; i++)
{
PR_WaitCondVar(g_condA, PR_INTERVAL_NO_TIMEOUT);//等待A的通知
printf("In thread B %d: %s\n", i,buf);
PR_NotifyCondVar(g_condB);//B处理事件快,立即通知告诉别人说B完成了
}
PR_Unlock(g_lock);
}
int main(int argc, char* argv[])
{
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
//start_time = PR_IntervalNow();
//printf("start time:%f\n", (double)PR_IntervalToMicroseconds(PR_IntervalNow() - start_time));
PRThread* p_tha;
PRThread* p_thb;
g_lock = PR_NewLock();
g_condA = PR_NewCondVar(g_lock);
g_condB = PR_NewCondVar(g_lock);
//g_monitor = PR_NewMonitor(); // 初始化monitor
p_tha = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_A,
"buffer to thread A",
PR_PRIORITY_HIGH,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
//printf("Thread A created time:%f\n", (double)PR_IntervalToMicroseconds(PR_IntervalNow() - start_time));
p_thb = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_B,
"buffer to thread B",
PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
//printf("Thread B created time:%f\n", (double)PR_IntervalToMicroseconds(PR_IntervalNow() - start_time));
PR_JoinThread(p_tha);
//printf("Thread A dead time:%f\n", (double)PR_IntervalToMicroseconds(PR_IntervalNow() - start_time));
PR_JoinThread(p_thb);
//printf("Thread B dead time:%f\n", (double)PR_IntervalToMicroseconds(PR_IntervalNow() - start_time));
PR_DestroyLock(g_lock);
PR_DestroyCondVar(g_condA);
PR_DestroyCondVar(g_condB);
PR_Cleanup();
return 0;
}
三. PRMonitor
#include "prmon.h"
//新建一个monitor(初始化),monitors 是用条件变量实现的可重用的锁 ,
//可能返回NULL(如果内存不足或其它系统资源不足的话)
NSPR_API(PRMonitor*) PR_NewMonitor(void);
//销毁一个monitor ,一定要等到不再使用了再销毁.与PRLock一样.
NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon);
//进入monitor ,并且Lock,不允许其它线程进入,如果本线程已经进入了monitor,那入计数就会加1
NSPR_API(void) PR_EnterMonitor(PRMonitor *mon);
//退出monitor,计数减1.当计数减为0时,则Unlock.
//如果多次进入Moniter,那么就要多次退出Moniter.不然不会Unlock.
//其它线程也就不能得到monitor
NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon);
//先清零计数.然后当前线程暂停,进入等待(_PR_WaitCondVar).当得到其它线程通知或超时后返回
//并恢复计数,线程重新运行.(好像要等通知线程退出monitor才可以重新变为活跃线程)(这里不清楚)
//如果没有进入monitor则返回PR_FAILURE.
//如果ticks为PR_INTERVAL_NO_TIMEOUT则会一直等待.
NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks);
//通知正在等待的线程,(好像不会管有没有收到通知,即便是没有等待线程也会返回)
NSPR_API(PRStatus) PR_Notify(PRMonitor *mon);
//通知所有正在待待的线程.
NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon);
//例程(有问题,对Lock的机制还不清楚)
#include "nspr.h"
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plc4.lib")
PRMonitor* g_monitor;
void Thread_A(char* buf)
{
PR_EnterMonitor(g_monitor);
for (int i = 0; i != 10; i++)
{
printf("In thread A %d: %s\n", i,buf);
}
PR_Sleep(5000);
PR_Notify(g_monitor);
PR_ExitMonitor(g_monitor);
}
int main(int argc, char* argv[])
{
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
PRThread* p_tha;
g_monitor = PR_NewMonitor();
PR_EnterMonitor(g_monitor);
p_tha = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_A,
"buffer to thread A",
PR_PRIORITY_HIGH,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
PR_Wait(g_monitor, PR_INTERVAL_NO_TIMEOUT);
printf("after PR_Wait!") ;
PR_ExitMonitor(g_monitor);
PR_JoinThread(p_tha);
PR_DestroyMonitor(g_monitor);
PR_Cleanup();
return 0;
}
三. Cache Monitor
#include "prcmon.h"
// 保护*address 必须用PR_CExitMonitor退出.一一对应
NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address);
//对应于PR_CEnterMonitor
NSPR_API(PRStatus) PR_CExitMonitor(void *address);
//等待一个量,与PR_Wait类似
NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout);
//与向PR_CWait发信号,
NSPR_API(PRStatus) PR_CNotify(void *address);
//向所有PR_CWait发信号
NSPR_API(PRStatus) PR_CNotifyAll(void *address);
//例程(vc2008)
#include "nspr.h"
#pragma comment(lib,"nspr4.lib")
#pragma comment(lib,"plc4.lib")
int x = 0;
void Thread_A(char* buf)
{
PR_CEnterMonitor(&x);
printf("In thread A %d: %s\n", x, buf);
PR_Sleep(5000);
PR_CNotify(&x);
PR_CExitMonitor(&x);
}
int main(int argc, char* argv[])
{
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
PRThread* p_tha;
p_tha = PR_CreateThread(PR_USER_THREAD,
(void (PR_CALLBACK *)(void *))Thread_A,
"buffer to thread A",
PR_PRIORITY_HIGH,
PR_LOCAL_THREAD,
PR_JOINABLE_THREAD,
0);
PR_CEnterMonitor(&x);
PR_CWait(&x, PR_INTERVAL_NO_TIMEOUT);
printf("after waiting\n");
PR_CExitMonitor(&x);
PR_JoinThread(p_tha);
PR_Cleanup();
return 0;
}