我正面临与pthread的同步问题。 threadWaitFunction1,是一个线程等待函数。
我希望行没有。 247 flag = 1
只有在243-246完成后才能执行。
但我觉得很奇怪,有时候,它会在243-246结束之前直接跳到247。
请帮帮我。
提前致谢。
236 struct timespec timeToWait;
237 static void* threadWaitFunction1(void *timeToWaitPtr)
238 {
239 cout << "Setting flag =0 inside threadWaitFunction1\n";
240
241 cout << "Inside threadWaitFunction\n";
242 struct timespec *ptr = (struct timespec*) timeToWaitPtr;
243 pthread_mutex_lock(&timerMutex);
flag = 0;
244 pthread_cond_timedwait(&timerCond, &timerMutex, ptr);
flag=1;
245 pthread_mutex_unlock(&timerMutex);
246 cout << "Setting flag =1 inside threadWaitFunction1\n";
247
248
249 }
创建并调用上述线程的线程是:
263 static void timer_trackStartTime ()
264 {
265 struct timeval now;
266 pthread_t thread;
267
268 printf("Inside trackStartTime: flag = %d\n",flag);
269
270 /* Setting timer expiration */
271 timeToWait.tv_sec = lt_leak_start_sec;; // First expiry after 1 sec
272 timeToWait.tv_nsec = lt_leak_start_nsec;
273 pthread_create(&thread, NULL, threadWaitFunction1, &timeToWait);
274 pthread_join(thread, NULL);
275 //pthread_kill(thread, SIGKILL); // Destroying the thread to ensure no leaks
276
.
.
283 }
如果我使用pthread_mutex_lock保护整个函数,但仍然存在同样的问题。如何确保有序执行?有人可以帮忙吗?
编辑:now.tv_sec和now.tv_nsec已从代码中删除。 * 编辑:更改了互斥锁内的标志(仍然不起作用) *
答案 0 :(得分:5)
所以这不是真正的执行顺序(这很可能是正确的),但时间让你不高兴。并且在“它在243-246完成之前直接跳到247”你的意思是“我观察它在它应该等待244的时间之前执行247”。正确?
然后,我怀疑这是spurious wakeup的问题:即使没有其他线程发信号通知条件变量,线程也可能被唤醒。 The specification of pthread_cond_timedwait()
表示“可能会发生来自pthread_cond_timedwait()或pthread_cond_wait()函数的虚假唤醒。”
通常,条件变量与应用程序中的某个事件相关联,并且等待条件变量的线程实际上等待另一个线程发出感兴趣事件的信号。如果您没有活动并且只想等待一段时间,那么其他方式(例如usleep()
或timers)更合适,除非您还需要pthread取消点。< / p>
补充:由于您对usleep()
感到满意,并且只询问为什么pthread_cond_timedwait()
无法满足您的期望,我决定不发布代码。如果您需要,可以使用@Hasturkun的答案。
ADDED-2:下面评论中的输出(在应用Hasturkun解决方案后获得)表明等待线程不会退出循环,这可能意味着pthread_cond_timedwait()
返回的内容与ETIMEDOUT不同。您是否看过@nos对您帖子的评论(我修正了减去纳米的数量):
确保(now.tv_usec * 1000)+ lt_leak_start_nsec;没有溢出。您只能将tv_nsec设置为max 999999999,如果表达式大于此值,则应从tv_nsec中减去1000000000,并将tv_sec增加1.如果timeToWaitPtr包含无效的tv_nsec(大于999999999),则pthread_cond_timedwait将失败(您应该检查它的返回值也是。) - 4月28日19:04
在这种情况下,pthread_cond_timedwait()
将重复返回EINVAL
,并且永远不会退出循环。最好在进入等待循环之前调整超时,但也可以在响应EINVAL
时完成。
ADDED-3:现在,在您更改问题中的代码以传递超时而不添加当前时间之后,它还有另一个问题。如the spec中所述,pthread_cond_timedwait()
的超时是绝对时间,而不是相对时间;所以当你超时时传递3秒这样的东西时,它被解释为“自系统时间参考点起3秒”。那个时刻几乎肯定会过去一段时间,因此pthread_cond_timedwait()
会立即返回
我建议你仔细阅读规范(包括理由),以便更好地理解如何使用这个函数。
答案 1 :(得分:3)
Paul E. McKenney写了一本名为"Is Parallel Programming Hard, And, If So, What Can You Do About It?"的书,它在记忆障碍方面有很好的信息(以及一些不错的图片)。
回到你的问题,flag
不受任何保护。虽然您可能认为pthread_mutex_lock()
和pthread_mutex_unlock
提供了一些强大的排序和可见性保证,但它提供的唯一保证是关键区域内部和互斥体本身的访问。
更重要的是,在某些体系结构pthread_mutex_lock()
上使用了获取障碍,pthread_mutex_unlock()
使用了释放障碍,这意味着互斥保护区域之前和之后的访问可能会溢出到互斥保护区域。在释放互斥锁的CPU和获取相同互斥锁的另一个CPU之间提供了强有序的保证,但几乎所有其他东西都不需要(也许没有得到)如此强大的保证。
显然我对pthreads有误,他们似乎需要完全的内存障碍(如果你解释将内存与其他线程同步那么需要)。关于这一点的更多信息,以及Hans Boehm在Reordering Constraints for Pthread-Style Locks实际实施中提供的保证的一些信息。
答案 2 :(得分:1)
如Alexey Kukanov所述,这个问题可能是虚假的唤醒。您的代码可能会被更正为循环,直到超时发生。请注意,我还将标志设置移动到互斥锁下。
static void* threadWaitFunction1(void *timeToWaitPtr)
{
struct timespec *ptr = (struct timespec*) timeToWaitPtr;
int ret;
pthread_mutex_lock(&timerMutex);
cout << "Setting flag =0 inside threadWaitFunction1\n";
flag=0;
cout << "Inside threadWaitFunction\n";
while (pthread_cond_timedwait(&timerCond, &timerMutex, ptr) != ETIMEDOUT)
;
cout << "Setting flag =1 inside threadWaitFunction1\n";
flag=1;
pthread_mutex_unlock(&timerMutex);
}
为了安全起见,您应该检查相同互斥锁下的标志以建立排序
答案 3 :(得分:0)
这可能是因为编译器优化了一些东西并在线程互斥之前将你的赋值放到了你的标志上。如果您想保证执行顺序(通常不能保证,在程序的可见行为不会因优化而改变的唯一条件下),您可以使用内存屏障来制作确保您希望按照编写顺序执行的指令仅按该顺序执行。
Here是一篇非常有趣的文章,虽然是技术性的,但却很长,关于内存障碍如何运作以及它们做什么和不做什么的文章。它是为Linux编写的,但基本原理保持不变。
编辑:
锁是一个隐含的内存屏障,我之前给出的链接,所以不需要内存屏障。
答案 4 :(得分:0)
仅供大家参考:
使用pthread_cond_timedwait(&timerCond, &timerMutex, ptr);
我无法实现的目标我使用usleep( )
,usleep采用timespec
结构,我们可以使用秒和纳秒来指定等待时间,以及我的目的已经解决了。
那么pthread_cond_timedwait(&timerCond, &timerMutex, ptr);
对于什么有意义?我很惊讶,因为这个API有望使调用线程等待,满足条件,但似乎处理器跳转到下一条指令作为优化措施,并且不等待条件满足。
但问题仍然存在,至于为什么pthread_cond_timedwait(&timerCond, &timerMutex, ptr);
不应该让调用线程等待?
我似乎浪费了这一API的一天:pthread_cond_timedwait( )