假设主线程为main,主线程开启的线程为A。1、main和A会访问同一种资源,A线程中写,B线程中读,比如全局变量int g_Some。
main和A之间是否需要同步?
2、程序中定义了某个全局函数void globalFuc()。
void globalFuc()
{
......
读取全局变量的代码
}
main线程中某处会调用到globalFuc函数,我的问题是——
是否需要
EnterCriticalSection(&cs);
globalFunc();
LeaveCriticalSection(&cs);
也就是说,main线程的时间片会不会在程序正执行到全局函数globalFunc中的某处代码时到期,从而使线程A执行?
3、main线程中若干处会读取g_Some的值,像下边这样:
int someValue1=g_Some;
......
......
用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......
问题是:怎样同步?是这样?
第一种——
EnterCriticalSection(&cs);int someValue1=g_Some;
......
......
......
用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......LeaveCriticalSection(&cs);还是?第二种——
EnterCriticalSection(&cs);int someValue1=g_Some;//引出问题——这里是否需要同步??只有一行代码LeaveCriticalSection(&cs);......
......
......EnterCriticalSection(&cs);用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......LeaveCriticalSection(&cs);两种方式哪种较好?
由于最近项目中经常遇到这样的问题,自己没弄明白,很着急,恳请高手解答,万分感谢。
main和A之间是否需要同步?
2、程序中定义了某个全局函数void globalFuc()。
void globalFuc()
{
......
读取全局变量的代码
}
main线程中某处会调用到globalFuc函数,我的问题是——
是否需要
EnterCriticalSection(&cs);
globalFunc();
LeaveCriticalSection(&cs);
也就是说,main线程的时间片会不会在程序正执行到全局函数globalFunc中的某处代码时到期,从而使线程A执行?
3、main线程中若干处会读取g_Some的值,像下边这样:
int someValue1=g_Some;
......
......
用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......
问题是:怎样同步?是这样?
第一种——
EnterCriticalSection(&cs);int someValue1=g_Some;
......
......
......
用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......LeaveCriticalSection(&cs);还是?第二种——
EnterCriticalSection(&cs);int someValue1=g_Some;//引出问题——这里是否需要同步??只有一行代码LeaveCriticalSection(&cs);......
......
......EnterCriticalSection(&cs);用g_Some的值作某些计算或处理(此处有若干行代码都用到g_Some)
......LeaveCriticalSection(&cs);两种方式哪种较好?
由于最近项目中经常遇到这样的问题,自己没弄明白,很着急,恳请高手解答,万分感谢。
read()
{
LeaveCriticalSection(&cs);
int temp = g_global; // 读
EnterCriticalSection(&cs);
}write()
{
LeaveCriticalSection(&cs);
g_global = 10; // 写
EnterCriticalSection(&cs);
}
但为保险起见,还是不敢不加同步,看来线程同步确实比较麻烦。
我的程序大概有30000行左右代码,涉及到的全局变量很多,感觉主线程中需要加同步锁的地方太多了,搞的头有点大。
开的线程,主要是用于CAN总线数据的接收,接收到的数据保存到全局变量里。
主线程有需要的地方从全局变量中读数据,处理,有没有好一些的解决办法?
如果你所说的同一种资源单单是一个内部类型,比如Int 而你所谓的更新线程又足以及时调用的话 我个人觉得是没必要进行同步的,当然你如果非要加也没什么不可以,如果是自定义类型,比如结构体 那你最好还是加上同步;至于第二个问题 不好意思 没细看 所答非所问了 但是我觉得如果你只是为了保证界面更新数据的一致性的话,你是不是可以考虑一下这样写:EnterCriticalSection(&cs); int someValue1=g_Some; LeaveCriticalSection(&cs); 以后所有的处理你都用someValue1 而不是再去访问g_Some,如果此时g_Some有更新的话会在下一次主线程函数得以执行的时候将其更新上去,这样不知道能不能满足你的要求。还有各位大神啊 1楼的所谓的同步起到效果了么? 打比方说 A B两个线程 A进入临界区但没出来,这时候A的时间片到期,B线程执行,上来直接先退出临界区了,根本没起到作用啊。
给你举个例子:long g_X = 0;
DOWRD WINAPI ThreadFunc1(PVOID pvParam){
g_x++;
return(0);
}
DOWRD WINAPI ThreadFunc2(PVOID pvParam){
g_x++;
return(0);
}在这个代码中,声明了一个全局变量g_x,并将它初始化为0。现在,假设创建两个线程,
一个线程执行ThreadFunc1,另一个线程执行ThreadFunc2。这两个函数中的代码是相同的,它
们都将1添加给全局变量g_x。因此,当两个线程都停止运行时,你可能希望在g_x中看到2这个
值。但是你真的看到了吗?回答是,也许看到了。根据代码的编写方法,你无法说明g_x中最
终包含了什么东西。
当两个线程都将g_x的值递增之后, g_x中的值就变成了2。这很好,并且正是我们希望的:
即取出零( 0),两次将它递增1,得出的值为2。太好了。不过不要急,Windows是个抢占式多
线程环境。一个线程可以随时中断运行,而另一个线程则可以随时继续执行。这样,上面的代
码就无法完全按编写的那样来运行。如果代码按这种形式来运行, g_x中的最后值就不是2,而是你预期的1。这使人感到非常
担心,因为你对调度程序的控制能力非常小。实际上,如果有100个线程在执行相同的线程函
数,当它们全部退出之后, g_x中的值可能仍然是1。显然,软件开发人员无法在这种环境中工
作。我们希望在所有情况下两次递增0产生的结果都是2。另外,不要忘记,编译器生成代码的
方法,哪个CPU在执行这个代码,以及主计算机中安装了多少个CPU等因素,决定了产生的结
果可能是不同的。这就是该环境的运行情况,我们对此无能为力。但是, Windows确实提供了
一些函数,如果正确地使用这些函数,就能确保产生应用程序的代码得到的结果。
为了解决上面的问题,需要某种比较简单的方法。我们需要一种手段来保证值的递增能够
以原子操作方式来进行,也就是不中断地进行。互锁的函数家族提供了我们需要的解决方案。
互锁的函数尽管用处很大,而且很容易理解,却有些让人望而生畏,大多数软件开发人员用得
很少。所有的函数都能以原子操作方式对一个值进行操作。让我们看一看下面这个InterlockedExchangeAdd函数:LONG InterlockedExchangeAdd(
PLONG plAddend,
LONG lIncrement);
这是个最简单的函数了。只需调用这个函数,传递一个长变量地址,并指明将这个值递增
多少即可。但是这个函数能够保证值的递增以原子操作方式来完成。因此可以将上面的代码重
新编写为下面的形式:long g_x = 0;
DOWRD WINAPI ThreadFunc1(PVOID pvParam){
InterlockedExchangeAdd(&g_x,1);
return (0);
}
DOWRD WINAPI ThreadFunc2(PVOID pvParam){
InterlockedExchangeAdd(&g_x,1);
return (0);
}
通过这个小小的修改,g_x就能以原子操作方式来递增,因此可以确保g_x中的值最后是2。当然楼主用的关键代码段也是一种线程同步的方法。
自己权衡下如果同时有多个线程对其进行操作会有什么样的结果。在你所顾虑的场景中,只有两种可能 A在读的时候中断,B写。B写的时候中断 A读。
线程A读 g_Some,读到一半被中断,线程B改了g_Some,这种情况我们说 A读到了脏数据。
如果加锁 A读g_Some,B尝试修改。B被中断,A读完g_Some,B恢复 修改 g_Some,这样A读到的依然是B修改前的。加锁是有代价的,不是无偿的。自己模拟下运行的整个过程,权衡得失,你才能把控多线程的本质。而不是一味的去问。