Pthread 在 C 中意外执行
Pthread execute unexpectedly in C
我想让 pthreads 可以运行它们的任务按指定的顺序:
线程 1 -> 线程 3 -> 线程 2
当我运行我的代码时,我发现结果不固定。
我的 OS 是 Ubuntu 16.04
有时结果是(意料之外的):
Before creating the threads
In thread1
In thread2
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
In thread3
有时结果是(预期的):
Before creating the threads
In thread1
In thread2
In thread3
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
下面是我的代码:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <signal.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond1, &lock1);
printf("I am thread1 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond2, &lock2);
printf("I am thread2 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond3, &lock3);
printf("I am thread3 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
void my_alarm_handler(int a)
{
TRUE = 0;//重新設定
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
signal( SIGALRM, my_alarm_handler );
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
alarm(1);
//TRUE = 0;/* Stop all the thread */
/* this is how we join thread before exit from a system */
printf("!!!!!!!!!!!!!!!!!!\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
return 0;
}
什么错误导致结果不固定?
提前致谢!
在条件(通常是循环)之外使用 pthread_cond_wait
测试依赖于互斥锁保护的状态的某些条件总是错误。在评论中,dragosht 指出:
You're not waiting for thread1 to wait on the condition variable
但是没办法"wait on a thread to wait on the condition variable"。相反,如果线程等待的条件已经满足,则线程不得等待条件变量。
相反,您应该这样做:
while (next_to_run != MY_NUMBER)
pthread_cond_wait(&cond, &lock);
并且信号线程应该在发出信号之前设置 next_to_run
(保持互斥量)。
您错误地使用了条件变量。正如 the Linux manual page for pthread_cond_wait()
所说:
When using condition variables there is always a Boolean predicate
involving shared variables associated with each condition wait that is
true if the thread should proceed. Spurious wakeups from the
pthread_cond_timedwait()
or pthread_cond_wait()
functions may occur.
Since the return from pthread_cond_timedwait()
or pthread_cond_wait()
does not imply anything about the value of this predicate, the
predicate should be re-evaluated upon such return.
这意味着线程将 pthread_cond_wait()
中的 returning 解释为它应该继续的指示是不合适的。相反,它应该将这样的 return 解释为它应该 检查 一些涉及一个或多个共享变量的条件以确定它是否应该继续的标志。如果条件不满足,那么通常情况下,它应该再等一段时间。在第一次等待之前检查条件通常也是合适的,以避免错过信号。
当然,对共享变量的所有访问都应该在同一个互斥体的保护下执行,至少在其中任何一个可能是写入的情况下。
在接收方,一切看起来像这样:
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
_Bool should_proceed1 = 0;
void *thread1(void *arg) {
pthread_mutex_lock(&lock1);
while (!should_proceed1) {
pthread_cond_wait(&cond1, &lock1);
}
pthread_mutex_unlock(&lock1);
// ...
}
在信令方面,它可能看起来像这样:
pthread_mutex_lock(&lock1);
should_proceed1 = 1;
pthread_mutex_unlock(&lock1);
pthread_cond_signal(&cond1);
注意,共享变量should_proceed1
在两个地方都在同一个互斥锁的保护下被访问,这也是等待线程与CV相关联的互斥锁以进行等待。此外,pthread_cond_signal()
调用也可以发生在互斥锁保护区内——您不必先解锁互斥锁——但是尽管等待线程会立即唤醒(如果有的话),它会在它可以重新获取互斥锁之前不要继续。
我想让 pthreads 可以运行它们的任务按指定的顺序:
线程 1 -> 线程 3 -> 线程 2
当我运行我的代码时,我发现结果不固定。 我的 OS 是 Ubuntu 16.04
有时结果是(意料之外的):
Before creating the threads
In thread1
In thread2
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
In thread3
有时结果是(预期的):
Before creating the threads
In thread1
In thread2
In thread3
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
下面是我的代码:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <signal.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond1, &lock1);
printf("I am thread1 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond2, &lock2);
printf("I am thread2 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond3, &lock3);
printf("I am thread3 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
void my_alarm_handler(int a)
{
TRUE = 0;//重新設定
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
signal( SIGALRM, my_alarm_handler );
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
alarm(1);
//TRUE = 0;/* Stop all the thread */
/* this is how we join thread before exit from a system */
printf("!!!!!!!!!!!!!!!!!!\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
return 0;
}
什么错误导致结果不固定?
提前致谢!
在条件(通常是循环)之外使用 pthread_cond_wait
测试依赖于互斥锁保护的状态的某些条件总是错误。在评论中,dragosht 指出:
You're not waiting for thread1 to wait on the condition variable
但是没办法"wait on a thread to wait on the condition variable"。相反,如果线程等待的条件已经满足,则线程不得等待条件变量。
相反,您应该这样做:
while (next_to_run != MY_NUMBER)
pthread_cond_wait(&cond, &lock);
并且信号线程应该在发出信号之前设置 next_to_run
(保持互斥量)。
您错误地使用了条件变量。正如 the Linux manual page for pthread_cond_wait()
所说:
When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the
pthread_cond_timedwait()
orpthread_cond_wait()
functions may occur. Since the return frompthread_cond_timedwait()
orpthread_cond_wait()
does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
这意味着线程将 pthread_cond_wait()
中的 returning 解释为它应该继续的指示是不合适的。相反,它应该将这样的 return 解释为它应该 检查 一些涉及一个或多个共享变量的条件以确定它是否应该继续的标志。如果条件不满足,那么通常情况下,它应该再等一段时间。在第一次等待之前检查条件通常也是合适的,以避免错过信号。
当然,对共享变量的所有访问都应该在同一个互斥体的保护下执行,至少在其中任何一个可能是写入的情况下。
在接收方,一切看起来像这样:
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
_Bool should_proceed1 = 0;
void *thread1(void *arg) {
pthread_mutex_lock(&lock1);
while (!should_proceed1) {
pthread_cond_wait(&cond1, &lock1);
}
pthread_mutex_unlock(&lock1);
// ...
}
在信令方面,它可能看起来像这样:
pthread_mutex_lock(&lock1);
should_proceed1 = 1;
pthread_mutex_unlock(&lock1);
pthread_cond_signal(&cond1);
注意,共享变量should_proceed1
在两个地方都在同一个互斥锁的保护下被访问,这也是等待线程与CV相关联的互斥锁以进行等待。此外,pthread_cond_signal()
调用也可以发生在互斥锁保护区内——您不必先解锁互斥锁——但是尽管等待线程会立即唤醒(如果有的话),它会在它可以重新获取互斥锁之前不要继续。