我想创建两个线程,它们应该是这样的:
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;
}
答案 0 :(得分:5)
多线程时不能依赖时序假设。
对这个问题的一个解释是,循环中printf
s的序列执行的时间非常短,可以在给予该线程的时间量内执行。
答案 1 :(得分:3)
我对线程的理解是错误的还是我的代码不等同于问题?
都不是。您的两个线程恰好按照预期的方式安排在您的系统上。显而易见的同步有很多原因,但由于OS调度程序在系统繁忙时会暂停一个或多个线程,因此它是相当不可预测的。您可以尝试在运行示例程序的同时跨多个线程运行繁重的工作负载,并查看是否存在问题。
这就是多线程程序中出现数千个意外错误的原因,也是我们需要互斥锁,信号量,原子写入和复杂线程调试工具(如helgrind或其等价物)的原因。在处理线程共享数据时,证明没有死锁或其他同步问题是非常困难的事情。
答案 2 :(得分: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;
}