我有以下代码尝试(和失败)来保护我的代码中的关键区域。基本上我希望任何线程在任何其他线程打印另一个语句之前完全执行print语句。
在main.h
:
pthread_mutex_t printer_mutex;
在main.c
中 - 该计划的第一件事:
pthread_mutex_init(&printer_mutex, NULL);
线程是这样创建的(虽然我删除了一些检查):
for(long t = 0; t < NUM_THREADS; t++) {
args[t].fw = fw;
args[t].deriv_init = deriv_init;
args[t].to_prove = fw.to_prove.at(i);
pthread_create(&threads[t], NULL, do_derivation_helper, (void *) &args[t]);
}
for(long t = 0; t < NUM_THREADS; t++) {
pthread_join(threads[t], NULL);
}
然后在我的一个类中执行程序中的所有打印,我有以下内容。打印应该锁定,然后在完成后解锁。
void InfoViewer::rule_x_fires() {
// START CRITICAL REGION
pthread_mutex_lock(&printer_mutex);
cout << "INFO: Rule x fires" << endl;
pthread_mutex_unlock(&printer_mutex);
// END CRITICAL REGION
}
我得到的不良输出是:
INFO: Rule x firesINFO: Rule x fires
即。在其他线程开始打印之前,该行未结束。
有什么想法吗?我没有正确初始化吗?我可以在我的C ++程序中使用标准的C风格线程吗?
答案 0 :(得分:8)
我认为问题出在定义头文件中的互斥变量。这样每个编译单元都可以获得自己的变量版本,并且只需锁定不同的互斥锁即可。只需这样做:
// .h header file: declare
extern pthread_mutex_t printer_mutex;
// one of the .c/.cpp files: define
pthread_mutex_t printer_mutex;
要解释为什么它“有效”多个定义 - 可以通过两种不同的方式初始化PThread互斥锁 - 动态地使用pthread_mutex_init
,静态地使用PTHREAD_MUTEX_INITIALIZER
。查看pthread.h
可以找到以下内容(32位版本):
# define PTHREAD_MUTEX_INITIALIZER \
{ { 0, 0, 0, 0, 0, { 0 } } }
这意味着任何类型为pthread_mutex_t
的静态变量都将被正确初始化,而不会分配任何显式值,或者由于静态内存为零填充而导致初始化。因此,您显式动态初始化了一个互斥锁,其他所有互斥锁都被隐式初始化为全零。
答案 1 :(得分:4)
您始终可以将std::cout
的使用更改为printf()
。您使用的是Mac,符合POSIX标准的操作系统。 printf()
保证是原子的。实际上,如果您可以使用printf
使得一次生成的所有输出都由单个printf()
调用执行,则您甚至不需要互斥锁。 std::cout
无法保证。无。
如果您确实将此std::cout
的特定用途转换为printf
,则应在整个申请过程中执行此操作。混合std::cout
和printf
不是最好的主意。
答案 2 :(得分:0)
这是一个有趣的问题。我不认为这解决了根问题(ostream中的同步),但试试这个:
void InfoViewer::rule_x_fires() {
// START CRITICAL REGION
pthread_mutex_lock(&printer_mutex);
cout << "INFO: Rule x fires" << endl;
cout.flush();
pthread_mutex_unlock(&printer_mutex);
// END CRITICAL REGION
}