数据同步控制

原创 2006年05月23日 22:05:00

        在说数据同步控制之前,先提一个小小的概念,线程安全函数,我们在多线程开发工作中,常常要面对这个概念,究竟什么是线程安全函数,我的理解是该函数在多线程环境中输出结果是稳定的(结果唯一),原来c运行库中没有考虑到多线程环境,因此有一些线程不安全函数:strtok,_wcstok,asctime,_strerror等,为了解决这个问题后来推出了多线程C运行库。从本质上来讲,造成这些问题的根本原因是多线程对一些共享资源的访问是非原子操作(非独占操作),因此,要解决这个问题就是我们今天要说的数据同步控制;

用户态同步控制方法:

1)原子操作:互锁的函数家族

      InterlockedExchangeAdd(PLONG plAdend, LONG lIncement);

      InterlockedExchangePoint(PVOID* ppvTarget,PVOID pvValue);

2) 关键代码段(用户态同步)

     CRITICAL_SECTION g_cs;

     InitializeCriticalSection(&g_cs);

     EnterCriticalSection(&g_cs);

     .......

     LeaveCriticalSection(&g_cs);

   注意点:

(1) EnterCriticalSection(&g_cs)函数阻塞时间是由注册表中(HLM/system/CurrentControlSet/Control/Session Manager)的CriticalSectionTimeout决定;

(2)对于多个共享资源的访问,使用多个关键代码段,函数中调用EnterCriticalSection的顺序相同,否则有死锁的可能;

(3) TryEnterCriticalSection(&g_cs)该函数不允许调用线程进入等待状态;它立即返回表明资源占用情况,被占用返回FALSE,否则返回TRUE;

关键代码与循环锁

如果线程试图占有另一个线程拥有的关键代码段时,调用线程就立即置为等待状态;线程必须从用户态转入为内核态(大约1000个CPU周期),是很大代价的;为了克服这种直接转入内核态所带来的大代价,引入了循环锁,因此当EnterCriticalSection函数被调用时,它先使用循环锁进行循环,以便多次取得该资源,只有所有尝试失败后,该线程才进入等待状态;目前对多处理器机器才有改善性能,单处理器循环锁没有任何性能改进,因为在循环过程中,拥有资源的线程根本无法释放;

引入循环锁的关键代码函数

(1)InitalizeCriticalSectionAndSpinCount(&g_cs,1000);//如果单处理器的话,1000会被忽略成0;

改变关键代码段循环次数

(2)SetCriticalSectionSpinCount(&g_cs,10000);

(3)关键代码的错误处理

     建议使用结构化异常处理方法;

上面介绍的都是用户态的同步方式,其局限性1)互锁家族函数只能对单值进行操作,根本不能使线程进入等待状态;2)关键代码段速度快,能使线程进入等待状态,但是无法设置等待超时,容易使之陷入死锁状态;下面介绍内核对象的同步方式

常见的内核对象

1)作业(job),进程,线程

2)文件,文件修改通知

3)互斥对象,事件,信号,可等待的定时器

等待函数 WaitForSingleObject(handle,timeout),WaitForMultipleObject(...)

等待函数可以使线程自愿进入等待状态,直到一个特定的内核对象为已通知状态为止;

等待的副作用

就是等待成功后会改变内核对象的当前通知,将内核对象置为未通知状态;等待的副作用是有用的,它保证多个线程等待同一内核对象时只从中唤醒一个,至于是哪一个,那就去问问microsoft啦:)

作业,进程,线程

一个布尔值表示其状态,运行时为未通知状态,终止时为通知状态

事件

比线程稍微复杂,其包含两个布尔值,除了通知状态外,还有自动重置标志;当自动重置的事件得到通知时,等待该事件的所有线程中一个线程变为可调度线程,当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程(全部激活);

CreateEvent(...),OpenEvent(...),CloseHandle(...),SetEvent(...),ResetEvent(...);

等待定时器

在某个时间或按规定时间间隔发出自己的信号通知的内核对象;

CreateWaitableTimer(),SetWaitableTimer()(只有调用这个函数才能设置定时器的通知发出)

信号内核对象

除了使用计数外,信号还包含两个带符号的32位值,一个是最大资源数量,一个是当前资源数量;其使用规则:

1)如果当前资源数量大于0时,信号发出通知;

2)如果当前资源数量等于0时,则不发出信号通知;

3)系统决不允许当前资源数量为负值;

4)当前资源数量决不能大于最大资源数量;

CreateSemaphore(...);//创建一个信号对象;

ReleaseSemaphore(...);//使信号当前使用资源数量进行递增;

等待信号的副作用是使信号的当前使用资源数递减1,这正是我们希望得到的:);

互斥对象

顾名思义,互斥对象就是确保线程拥有对单个资源的互斥访问权;其行为特性跟关键代码段一样;

CreateMetux(...)//创建一个互斥对象;

OpenMetux(...);//打开一个互斥对象;

ReleaseMetux(...);//释放一个互斥对象;

整个线程同步控制就介绍这么,下面举一个简单例子,利用互斥对象和信号对象实现一个线程安全的queue对象;

class CQueue{

public:

   struct ELEMENT{

   ....

};

private:

     PELEMENT    m_pElements;// array of elements to be processed;

     int                     m_nMaxElements;

    HANDLE         m_h[2];//metux & semphore handles;

    HANDLE        &m_hmtx0;

   HANDLE         &m_hsemNumElements;

public:

   CQueue();

  ~CQueue();

   BOOL Apend(PELEMENT pElement,DWORD dwTimeout);

   BOOL Remove(PELEMENT pElement,DWORD dwTimeout);

};

BOOL CQueue::Append(PELEMENT pElement,DWORD dwTimeout)

{

          DWORD dw = WaitForSingleObject(m_hmtx0,dwTimeout);

         if(dw == WAIT_OBJECT_0)

        {

                     LONG lPrevCount;

                    fOK = ReleaseSemphore(m_hsemNumElements,1,&lPrevCount);

                     ........

                     Release(m_hmtx0);

        }

        return TRUE;

}

BOOL CQueue::Remove(PELEMENT pElement,DWORD dwTimeout)

{

         BOOL fok=(WaitForMutipleObjects(2,m_h,TRUE,dwTimeout) == WAIT_OBJECT_0);

         if(fok)

        {

              *pElements=m_pElements[0];

             MoveMemory(&m_pElements[0],&m_pElements[1],sizeof(ELEMENT)*(m_nMaxElements -1));

            ReleaseMetux(m_hmtx0);

        }

       return TRUE;

}

that's over! : -)

Java 并发编程 同步控制 三

1、 重入锁 ReentrantLock synchronized 的重入锁: ReentrantLock。 重入锁需要手动进行加锁和解锁: lock 和unlock。public class...
  • chao_19
  • chao_19
  • 2017年06月25日 15:17
  • 88

总线的同步通信

总线的同步通信           通信双方由统一时标控制数据传送称为同步通信。这个公共的时钟可以由CPU总线控制部件发送到每一个部件(设备),也可以让每个部件有各自的时钟发生器,时标通常由CPU的...
  • ce123
  • ce123
  • 2011年11月07日 00:07
  • 4812

java同步控制

  • zhangyunsheng11
  • zhangyunsheng11
  • 2017年10月10日 19:15
  • 78

concurrent-2-同步控制

重入锁 ReentrantLock 重入锁示例 lock : 获取锁资源 unLock : 释放锁资源 //重入锁示例 public class TestReentrant...
  • csdn_ygy
  • csdn_ygy
  • 2017年05月26日 22:28
  • 104

线程同步控制

1.      Critical Section(关键区域、临界区域) 指一小块“用来处理一份被共享之资源”的程序代码。一次只能有一个线程获准访问资源。千万不要在一个critical section...
  • jeromeyu
  • jeromeyu
  • 2012年06月11日 21:25
  • 222

同步控制 EvenGenerator

通过在 EvenGenerator.java 中加入 synchronized关键字,我们就可以防止不希望 的线程访问:   //: c13:SynchronizedEvenGenerator....
  • u011282109
  • u011282109
  • 2013年08月30日 09:40
  • 407

多线程下数据状态的同步控制

线程同步没控制好,直接查询数据库表的tokenID,在同机构线程多并发时,运行时会产生误读,导致重复插入。 关于重复的问题, 让他们把查询token直接改成update 表名 Set token=开...
  • Ctrain
  • Ctrain
  • 2015年08月19日 18:29
  • 235

笔记学习各种同步控制工具的使用

2017年8月6号:java并发包1.学习各种同步控制工具的使用 ReentrantLock Condition Semaphore ReadWriteLock CountDownLatch Cycl...
  • heting717
  • heting717
  • 2017年08月06日 14:22
  • 159

java 线程中 常见笔试题

常见笔试题问题一:sleep与wait区别  其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题  在java.lang.thread类中,提供了sl...
  • inaoen
  • inaoen
  • 2010年12月24日 18:10
  • 765

HttpConnector 与 HttpProcessor 同步控制

HttpConnector 与 HttpProcessor 同步控制 Tomcat学习 HttpConnector和HttpProcessor启动流程和线程交互   一些疑问 1、对于assi...
  • cbjcry
  • cbjcry
  • 2017年04月13日 11:13
  • 123
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数据同步控制
举报原因:
原因补充:

(最多只允许输入30个字)