2013-12-16 68 views
4

我要创建两个线程,这都应该是这样的:关于并行POSIX线程

P1:

while(1) { 
    printf("1"); 
    printf("2"); 
    printf("3"); 
    printf("4"); 
} 
return NULL; 

P2:

while(1) { 
    printf("5"); 
    printf("6"); 
    printf("7"); 
    printf("8"); 
} 
return NULL; 

据我平行的知识它将不会打印12345678,而是由于缺乏同步而导致数字完全随机变化。

然而,当我试图复制它在真正的代码它使印刷1234了几下,然后切换到5678,打印了几次,并回到1234

是我线程的理解错误,或我的代码不等于问题?

void *print1(void *arg) { 
    while(1) { 
     printf("1"); 
     printf("2"); 
     printf("3"); 
     printf("4\n"); 
    } 
    return NULL; 
} 

void *print2(void *arg) { 
    while(1){ 
     printf("5"); 
     printf("6"); 
     printf("7"); 
     printf("8\n"); 
    } 
    return NULL; 
} 


int main() { 
    pthread_t tid1, tid2; 
    pthread_create(&tid1, NULL, print1, NULL); 
    pthread_create(&tid2, NULL, print2, NULL); 
    pthread_join(tid1, NULL); 
    pthread_join(tid2, NULL); 
    return 0; 

} 
+1

一个词:buffering。输出流不会隐式刷新,直到遇到新行。 – Kninnug

+0

我该怎么做? fflush(标准输出)?我相当新的 – Pulz

+0

你绝对可以尝试。虽然它可能仍然会产生相同的输出。请参阅答案以获得更多解释。 – Kninnug

回答

1

在多线程应用程序内部访问共享数据时,保护共享数据总是非常重要。在你的情况下,你有两个线程同时访问标准输出,因此你有一个竞争条件,其中两个线程竞相获取stdout。因此,我冒昧地让您的程序适应标准输出受互斥锁保护的情况。在使用stdout之前,我们锁定一个互斥锁,另一个线程也会尝试锁定互斥锁,但两者不能同时在同一时间完成。因此试图锁定的第二个线程进入睡眠状态。

正如其他人告诉你的,看起来你最初编写的程序做出了不错的输出,或多或少都是巧合,在其他系统上,你无法保证这一点,并且两个线程的输出可能混淆起来。在输出像

1256734 
8 
5671234 
8 

结束等

现在,你可能会认为,一旦互斥量被释放其他将自动接管,但最多也就是调度。因此在下面的例子中,程序在输出5678之前可能会执行几个1234。但它将始终是1234或5678,而这些输出不会混合。如果你真的想要交替两个线程,你必须有更复杂的输出和查找条件变量,例如,pthread API也支持这些。

#include<pthread.h> 
#include<stdio.h> 

void *print1(void *arg) { 
    pthread_mutex_t* lock = arg; 
    while(1) { 
     /*now we do output from one thread while we lock the 
     *mutex from the main function.*/ 
     pthread_mutex_lock(lock); 
     printf("1"); 
     printf("2"); 
     printf("3"); 
     printf("4\n"); 
     fflush(stdout); 
     /*now we must lock the lock, because otherwise 
     *the other thread can't lock the mutex and if 
     *we would try to lock the mutex again we would 
     *create a deadlock, hower recursive locking is 
     *possible, but beyond the scope of my anwer.*/ 
     pthread_mutex_unlock(lock); 
    } 
    return NULL; 
} 

void *print2(void *arg) { 
    /*see the note in the frist thread*/ 
    pthread_mutex_t* lock = arg; 
    while(1){ 
     pthread_mutex_lock(lock); 
     printf("5"); 
     printf("6"); 
     printf("7"); 
     printf("8\n"); 
     fflush(stdout); 
     pthread_mutex_unlock(lock); 
    } 
    return NULL; 
} 


int main() { 
    pthread_t tid1, tid2; 
    /*lets create a lock to protect our shared resources 
    *in this case the standard output. 
    */ 
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
    /*make sure that the mutex is available inside the thread 
    *by sending a pointer to the mutex as fourth argument to 
    *phtread_create.*/ 
    pthread_create(&tid1, NULL, print1, &lock); 
    pthread_create(&tid2, NULL, print2, &lock); 
    pthread_join(tid1, NULL); 
    pthread_join(tid2, NULL); 
    return 0; 
} 
5

多线程时,您不能依赖时序假设。

对此问题的解释是,循环内的printf s的执行时间很短,可以在给定的时间量内执行。

3

我对线程的理解是错误的还是我的代码不等于问题?

都没有。您的两个线程恰好按您预期的方式安排在您的系统上。有明显的同步有很多原因,但它是相当不可预测的,因为OS调度程序会在系统忙碌时暂停一个或多个线程。在运行示例程序的同时,您可能会尝试在多个线程中运行繁重的工作负载,并查看是否有些事情会感到困惑。

这是造成数千个多线程程序中意外错误的原因,也是我们需要互斥锁,信号量,原子写入和复杂线程调试工具(如helgrind或其等价物)的原因。在处理线程共享数据时,证明没有死锁或其他同步问题是非常困难的事情。

+0

“我们需要的原因”和helgrind☺ –

+0

@JonasWielicki好点;将添加。 – ldrumm