在查看代码错误时看到比较好的,进行记录
为什么很多人都用CRITICAL_SECTION实现锁
2014-09-19 20:37
如题。CRITICAL_SECTION只能用于不同线程的互斥,而不能用于同步。因为同一个线程可以多次EnterCriticalSection。。 为什么网上的代码,很多“锁”、“自动锁”的类,都是用CRITICAL_SECTION实现。 如果使用的人不熟悉这个,很容易就会用错呀。
回复讨论(解决方案)
这是我找的一份代码
/*********************************/ #ifdef _WIN32 #include <Windows.h> #else #include <pthread.h> #endif #ifdef _WIN32 #define LOCK_MUTEXT CRITICAL_SECTION #else #define LOCK_MUTEXT pthread_mutex_t #endif class CThreadLock { public: CThreadLock(void){ Init(); } ~CThreadLock(){ Close(); } void Lock(){ #ifdef _WIN32 EnterCriticalSection(&m_lock); #else pthread_mutex_lock(&m_lock); #endif } void UnLock(){ #ifdef _WIN32 LeaveCriticalSection(&m_lock); #else pthread_mutex_unlock(&m_lock); #endif } //protected: private: LOCK_MUTEXT m_lock; void Init(){ #ifdef _WIN32 InitializeCriticalSection(&m_lock); #else pthread_mutex_init(&m_lock); #endif } void Close(){ #ifdef _WIN32 DeleteCriticalSection(&m_lock); #else pthread_mutex_destroy(&m_lock); #endif } }; //定义一个自动加锁的类 CAutoLock{ public: CAutoLock(CThreadLock *pThreadLock){ m_pThreadLock=pThreadLock; if (NULL!=m_pThreadLock) { m_pThreadLock->Lock(); } } ~CAutoLock(){ if (NULL!=m_pThreadLock) { m_pThreadLock->UnLock(); } } private: CThreadLock * m_pThreadLock; }; /*********************************/ #endif
CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?
CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?
假如你有一个数据库连接池。该连接池有一个“获取一个空闲连接”的对外接口,这个函数肯定需要加锁。如果锁用CRITICAL_SECTION实现,外部某个线程用你这个连接池,假如他需要俩连接就可能会有问题。
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?
引用 2 楼 zilaishuichina 的回复:CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连接池。该连接池有一个“获取一个空闲连接”的对外接口,这个函数肯定需要加锁。如果锁用CRITICAL_……
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连接池。该连接池有一个“获取一个空闲连接”的对外接口,这个函数肯定需要加锁。如果锁用CRITICAL_……
如果A线程 需要2个连接
那代码的执行顺序就是
//代码段1
Enter
//分配连接
Leave
//代码段2
Enter
//分配连接
Leave
//代码段3
如果此时同时B线程也需要申请连接,也没有问题啊
没看出来问题在哪啊
引用 3 楼 yunchao630 的回复:
引用 2 楼 zilaishuichina 的回复:CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连接池。该连接池有一个“获取一个空闲连接”的对外接口,这个函数肯定需要加锁。如果……
嗯,你说的对。但是假如这个接口是异步的就不行了吧,我不是抬扛,实际使用中,其他需求可能会导致这样。
引用 2 楼 zilaishuichina 的回复:CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连接池。该连接池有一个“获取一个空闲连接”的对外接口,这个函数肯定需要加锁。如果……
我是在做windows嵌入式系统的驱动时,看到windows系统内核源码在做对象同步的时候通常都用的CRITICAL_SECTION,而且内核源码中还简单的封装好一个class,后来我就干脆把它保存起来,用于自己的项目中。
引用 4 楼 zilaishuichina 的回复:引用 3 楼 yunchao630 的回复:
引用 2 楼 zilaishuichina 的回复:CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连……
引用 2 楼 zilaishuichina 的回复:CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?假如你有一个数据库连……
异步的代码 也总有它需要顺序执行的地方
程序的执行流程无外乎顺序、分支、循环,总逃不出这三样的
所谓异步的实现,无外乎是
1、消息队列实现异步,逻辑需要的操作压入队列,一个一个的处理,处理完的callback。
2、链表定时轮询,处理完的callback。
不管是链表也好,队列也好,或者其他专门设计的容器也罢,那么只要这个容器有锁,不就又变回还是顺序的先后执行的情况了,异步的也没问题啊。
CriticalSection本来就是实现 一块资源只被一个线程使用的
比如说 A线程占用了那块资源 那么B线程就只能等A线程离开后B才能访问
如果LZ是想说 A,B线程都能同时访问的话
这可能就需要用到信号量来解决了。 不过应该只限于只读操作。。
比如说 A线程占用了那块资源 那么B线程就只能等A线程离开后B才能访问
如果LZ是想说 A,B线程都能同时访问的话
这可能就需要用到信号量来解决了。 不过应该只限于只读操作。。
《30天自制操作系统》
那楼主打算用什么实现锁呢?
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。
那楼主打算用什么实现锁呢?
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。
mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。
仅供参考
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer, //a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理, //在处理的时候每次从新buffer中取两个字节打印 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <process.h> #include <io.h> //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; void Lock(CRITICAL_SECTION *l) { EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) { LeaveCriticalSection(l); } void LogV(const char *pszFmt,va_list argp) { struct tm *now; struct timeb tb; if (NULL==pszFmt||0==pszFmt[0]) return; _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp); ftime(&tb); now=localtime(&tb.time); sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday); sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec ); sprintf(mss,"%03d",tb.millitm); printf("%s %s.%s %s",datestr,timestr,mss,logstr); flog=fopen(logfilename1,"a"); if (NULL!=flog) { fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr); if (ftell(flog)>MAXLOGSIZE) { fclose(flog); if (rename(logfilename1,logfilename2)) { remove(logfilename2); rename(logfilename1,logfilename2); } } else { fclose(flog); } } } void Log(const char *pszFmt,...) { va_list argp; Lock(&cs_log); va_start(argp,pszFmt); LogV(pszFmt,argp); va_end(argp); Unlock(&cs_log); } //Log} #define ASIZE 200 #define BSIZE 240 #define CSIZE 2 char Abuf[ASIZE]; char Cbuf[CSIZE]; CRITICAL_SECTION cs_HEX ; CRITICAL_SECTION cs_BBB ; struct FIFO_BUFFER { int head; int tail; int size; char data[BSIZE]; } BBB; int No_Loop=0; void HexDump(int cn,char *buf,int len) { int i,j,k; char binstr[80]; Lock(&cs_HEX); for (i=0;i<len;i++) { if (0==(i%16)) { sprintf(binstr,"%03d %04x -",cn,i); sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]); } else if (15==(i%16)) { sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]); sprintf(binstr,"%s ",binstr); for (j=i-15;j<=i;j++) { sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.'); } Log("%s\n",binstr); } else { sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]); } } if (0!=(i%16)) { k=16-(i%16); for (j=0;j<k;j++) { sprintf(binstr,"%s ",binstr); } sprintf(binstr,"%s ",binstr); k=16-k; for (j=i-k;j<i;j++) { sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.'); } Log("%s\n",binstr); } Unlock(&cs_HEX); } int GetFromRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) { int lent,len1,len2; lent=0; Lock(cs); if (fbuf->size>=len) { lent=len; if (fbuf->head+lent>BSIZE) { len1=BSIZE-fbuf->head; memcpy(buf ,fbuf->data+fbuf->head,len1); len2=lent-len1; memcpy(buf+len1,fbuf->data ,len2); fbuf->head=len2; } else { memcpy(buf ,fbuf->data+fbuf->head,lent); fbuf->head+=lent; } fbuf->size-=lent; } Unlock(cs); return lent; } void thdB(void *pcn) { char *recv_buf; int recv_nbytes; int cn; int wc; int pb; cn=(int)pcn; Log("%03d thdB thread begin...\n",cn); while (1) { Sleep(10); recv_buf=(char *)Cbuf; recv_nbytes=CSIZE; wc=0; while (1) { pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes); if (pb) { Log("%03d recv %d bytes\n",cn,pb); HexDump(cn,recv_buf,pb); Sleep(1); } else { Sleep(1000); } if (No_Loop) break;// wc++; if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc); } if (No_Loop) break;// } } int PutToRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) { int lent,len1,len2; Lock(cs); lent=len; if (fbuf->size+lent>BSIZE) { lent=BSIZE-fbuf->size; } if (fbuf->tail+lent>BSIZE) { len1=BSIZE-fbuf->tail; memcpy(fbuf->data+fbuf->tail,buf ,len1); len2=lent-len1; memcpy(fbuf->data ,buf+len1,len2); fbuf->tail=len2; } else { memcpy(fbuf->data+fbuf->tail,buf ,lent); fbuf->tail+=lent; } fbuf->size+=lent; Unlock(cs); return lent; } void thdA(void *pcn) { char *send_buf; int send_nbytes; int cn; int wc; int a; int pa; cn=(int)pcn; Log("%03d thdA thread begin...\n",cn); a=0; while (1) { Sleep(100); memset(Abuf,a,ASIZE); a=(a+1)%256; if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop send_buf=(char *)Abuf; send_nbytes=ASIZE; Log("%03d sending %d bytes\n",cn,send_nbytes); HexDump(cn,send_buf,send_nbytes); wc=0; while (1) { pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes); Log("%03d sent %d bytes\n",cn,pa); HexDump(cn,send_buf,pa); send_buf+=pa; send_nbytes-=pa; if (send_nbytes<=0) break;// Sleep(1000); if (No_Loop) break;// wc++; if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc); } if (No_Loop) break;// } } int main() { InitializeCriticalSection(&cs_log ); Log("Start===========================================================\n"); InitializeCriticalSection(&cs_HEX ); InitializeCriticalSection(&cs_BBB ); BBB.head=0; BBB.tail=0; BBB.size=0; _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1); _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2); if (!access("No_Loop",0)) { remove("No_Loop"); if (!access("No_Loop",0)) { No_Loop=1; } } while (1) { Sleep(1000); if (No_Loop) break;// if (!access("No_Loop",0)) { No_Loop=1; } } Sleep(3000); DeleteCriticalSection(&cs_BBB ); DeleteCriticalSection(&cs_HEX ); Log("End=============================================================\n"); DeleteCriticalSection(&cs_log ); return 0; }
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。
==>有道理
我记得EnterCriticalSection一开始会自旋,所以如果需要同步的操作时间比较短,那么CRITICAL_SECTION的效率更高
#ifdef _WIN32 EnterCriticalSection(&m_lock); #else pthread_mutex_lock(&m_lock); #endif
这种写法真蛋疼
建议搞个公共定义头,头里
#ifdef _WIN32 #define XXX_LOCK(x) EnterCriticalSection(&x); #else #define XXX_LOCK(x) pthread_mutex_lock(&x); #endif
下面就直接XXX_LOCK(m_lock),不用那么多#ifdef,看起来也舒服
使用临界区主要是因为高效,进不去的时候自旋,这里就有个dwSpinCount,是自旋次数,当达到这个值得时候,还进不去的话就要进入内核态挂起等待。切换到内核态较之线程context切换成本很高。
On multiprocessor systems, if the critical section is unavailable, the calling thread spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section。
On multiprocessor systems, if the critical section is unavailable, the calling thread spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section。
我是个初级菜鸟,来看看大鸟们怎么写程序
如题。CRITICAL_SECTION只能用于不同线程的互斥,而不能用于同步。因为同一个线程可以多次EnterCriticalSection。。 为什么网上的代码,很多“锁”、“自动锁”的类,都是用CRITICAL_SECTION实现。 如果使用的人不熟悉这个,很容易就会用错呀。
没错啊,很多时候用CRITICAL_SECTION 实现锁啊。锁的目的不就是对某一个资源的独享式占有。当然你也可以使用Mutex来实现锁。但是CRITICAL_SECTION是非内核对象(用户对象?不知怎么叫),Mutex是内核对象。内核对象的创建、释放、工作会比非内核对象慢,因为微软在实现这套机制时做了很多背后的工作,所以会慢。CRITICAL_SECTION的执行速度会更快,所以大家多数情况下使用CRITICAL_SECTION,除非需要跨进程来进行互斥或者锁才会使用Mutex。
这个链接讲的不错:http://blog.youkuaiyun.com/wwl33695/article/details/8349549
《Windows核心编程》
如题。CRITICAL_SECTION只能用于不同线程的互斥,而不能用于同步。因为同一个线程可以多次EnterCriticalSection。。 为什么网上的代码,很多“锁”、“自动锁”的类,都是用CRITICAL_SECTION实现。 如果使用的人不熟悉这个,很容易就会用错呀。
什么叫做不能用于同步?
你所理解的同步是什么??
同步是一个广泛概念,如果有N个线程,我想让这个N个线程按照一定的顺序去访问一个数据,我的这个需求就是要线程“同步”,所有的互斥,等待,异步执行等等都是可以为了实现一个目的而诞生的,这个目的就是“同步”。
同一个线程是可以多次EnterCriticalSection,但是系统会保证,如果有一个线程已经EnterCriticalSection成功了,那在这个线程LeaveCriticalSection之前,不会有第二个线程EnterCriticalSection,这就可以达到线程按照一定的顺序访问数据,这看起来也像互斥。
注意 Event(事件),Mutex(互斥量),Semaphore(信号量),WaitableTimer(可等待定时器)这些都是同步(Synchronization )对象,用于线程同步(Synchronization)。
至于你的问题,为什么常用临界区:因为上述同步对象都是内核对象,使用时会涉及到用户态和内核态的切换,所以开销比较大,而临界区是在用户态实现的一个轻量的同步机制,在使用时不会有频繁的内核态和用户态的切换,资源消耗很小,所以比较普遍。
引用 10 楼 wjb_yd 的回复:那楼主打算用什么实现锁呢?
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
你确定你理解“同步”的意思了么。。。
引用 11 楼 yunchao630 的回复:引用 10 楼 wjb_yd 的回复:那楼主打算用什么实现锁呢?
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
你确定你理解“同步”的……
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
你确定你理解“同步”的……
质疑我的观点的时候请说出你的观点。
回复你这种帖子浪费口水浪费时间浪费金钱。
引用 11 楼 yunchao630 的回复:引用 10 楼 wjb_yd 的回复:那楼主打算用什么实现锁呢?
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
你确定你理解“同步”的……
critical_section效率要高一些,因为是针对同一个进程的。
mutex是针对整个操作系统的。mutex也是不能用于同步的。信号量和事件才能做到同步。我只是想看看大家都想法。最近看了一遍同步和互斥,突然想到的这些。。。
你确定你理解“同步”的……
看错了,深表歉意。
但是还是建议发帖要质量。觉得别人的回复值得质疑就应该直接指出来,并且表述下自己的观点。
我觉得楼猪可以看看《Windows环境下32位汇编语言程序设计》
CRITICAL_SECTION本来就是用来
在多线程的情况下
保证一段代码一次只会被一个线程执行
同一个线程的多次EnterCriticalSection,必然是先后执行的,会有什么问题?
没问题啊,那连接就一个个地给,你理解的同步 难道是并发的意思?
这是我找的一份代码
测试了上面的代码,设置了个全局变量,如何在两个函数里面调用CThreadLock的lock和unlock,发现在第个函数里锁不住这个全局变量啊,如何第一个函数还没有解锁,第二个函数就进入到临界区了,这问题纠结一天了,就指点啊
/*********************************/ #ifdef _WIN32 #include <Windows.h> #else #include <pthread.h> #endif #ifdef _WIN32 #define LOCK_MUTEXT CRITICAL_SECTION #else #define LOCK_MUTEXT pthread_mutex_t #endif class CThreadLock { public: CThreadLock(void){ Init(); } ~CThreadLock(){ Close(); } void Lock(){ #ifdef _WIN32 EnterCriticalSection(&m_lock); #else pthread_mutex_lock(&m_lock); #endif } void UnLock(){ #ifdef _WIN32 LeaveCriticalSection(&m_lock); #else pthread_mutex_unlock(&m_lock); #endif } //protected: private: LOCK_MUTEXT m_lock; void Init(){ #ifdef _WIN32 InitializeCriticalSection(&m_lock); #else pthread_mutex_init(&m_lock); #endif } void Close(){ #ifdef _WIN32 DeleteCriticalSection(&m_lock); #else pthread_mutex_destroy(&m_lock); #endif } }; //定义一个自动加锁的类 CAutoLock{ public: CAutoLock(CThreadLock *pThreadLock){ m_pThreadLock=pThreadLock; if (NULL!=m_pThreadLock) { m_pThreadLock->Lock(); } } ~CAutoLock(){ if (NULL!=m_pThreadLock) { m_pThreadLock->UnLock(); } } private: CThreadLock * m_pThreadLock; }; /*********************************/ #endif