C++ 为什么休眠函数忽略了我程序中的一些顺序指令?
我已经实现了一个条件变量示例。但是,我看到,一旦pthread_cond_wait接收到信号,我就进入睡眠状态。睡眠后的代码不会执行。它直接跳到else条件。我知道互斥锁现在已解锁。我只有两个线程A和B。两个线程都有两个不同的启动例程。如果我在收到信号后在线程a中进行睡眠,那么它应该安排线程B。现在,一旦线程B完成。线程A应该在睡眠后从该位置恢复。然而,它不是从睡眠中恢复的。它重新获得锁。看看我的例子,它的输出。您会注意到以下几行从未打印过-要快速解决我的问题,请查看以下函数-void*Thread\u function\u A(void*Thread\u arg)和void*Thread\u function\u B(void*Thread\u arg)。其他功能并不那么重要C++ 为什么休眠函数忽略了我程序中的一些顺序指令?,c++,linux,multithreading,pthreads,C++,Linux,Multithreading,Pthreads,我已经实现了一个条件变量示例。但是,我看到,一旦pthread_cond_wait接收到信号,我就进入睡眠状态。睡眠后的代码不会执行。它直接跳到else条件。我知道互斥锁现在已解锁。我只有两个线程A和B。两个线程都有两个不同的启动例程。如果我在收到信号后在线程a中进行睡眠,那么它应该安排线程B。现在,一旦线程B完成。线程A应该在睡眠后从该位置恢复。然而,它不是从睡眠中恢复的。它重新获得锁。看看我的例子,它的输出。您会注意到以下几行从未打印过-要快速解决我的问题,请查看以下函数-void*Thre
The cond_wait is unblocked now
The thread A proceeds
Thread A unlocked
这是现在的节目-
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>
/** get pid **/
#include <sys/types.h>
#include <unistd.h>
/** kill signal **/
#include <signal.h>
using namespace std;
int shared_variable = 7;
pid_t pid_A;
pid_t pid_B;
class helium_thread
{
private:
pthread_t *thread_id;
pid_t process_pid;
public:
static pthread_mutex_t mutex_thread;
static pthread_cond_t cond_var;
void set_thread_id(pthread_t tid);
pthread_t *get_thread_id();
int create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg );
helium_thread();
~helium_thread();
};
helium_thread thread_1, thread_2;
/** The definition of the static member can't be inside a function, You need to put it outside **/
/** When I tried using inside a function, I got the error - error: invalid use of qualified-name ‘helium_thread::mutex_thread **/
pthread_mutex_t helium_thread::mutex_thread = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t helium_thread::cond_var = PTHREAD_COND_INITIALIZER;
void helium_thread::set_thread_id( pthread_t tid)
{
*(this->thread_id) = tid;
}
pthread_t * helium_thread::get_thread_id( )
{
return (this->thread_id);
}
int helium_thread::create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg )
{
int ret;
ret = pthread_create(thread_ptr,attr,start_routine,(void *)arg) ;
cout<<"Thread created "<<std::hex<<thread_ptr<<endl;
return ret;
}
helium_thread::helium_thread()
{
thread_id = new pthread_t;
cout<<"Constructor called "<<std::hex<<thread_id<<endl;
}
helium_thread::~helium_thread()
{
cout<<"Destructor called"<<std::hex<<thread_id<<endl;
delete thread_id;
}
/** While defining the methods of the class, Keywords static and virtual should not be repeated in the definition. **/
/** They should only be used in the class declaration. **/
void handler(int sig)
{
//do nothing
cout<<"Handler called"<<endl;
}
void *Thread_Function_A(void *thread_arg)
{
int rc = 0;
pid_A = getpid();
cout<<"The pid value of Thread A is"<< pid_A << endl;
while(1)
{
pthread_mutex_lock(&(helium_thread::mutex_thread));
cout<<"Thread A lock acquire first"<<endl;
if ( shared_variable != 5)
{
/** Now you put a sleep to introduce a race condition **/
/** You will find that there is no race condition here **/
cout<<"Going to conditional wait"<<endl;
//cout<<"Sleep thread A"<<endl;
//sleep(5);
pthread_cond_wait(&helium_thread::cond_var, &helium_thread::mutex_thread);
cout<<"Sleep after cond_wait"<<endl;
sleep(5);
cout<<"The cond_wait is unblocked now "<<endl;
cout<<"The thread A proceeds"<<endl;
cout<<"The shared_variable value = "<< std::dec<< shared_variable << endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout<<"Thread A unlocked"<<endl;
}
else
{
cout<<"Else condition thread A..shared variable value is "<<shared_variable<<endl;
cout<<"The condition of thread A is met now"<<endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout<<"Thread A unlocked in else condition"<<endl;
pthread_exit(NULL);
}
}
}
void *Thread_Function_B(void *thread_arg)
{
pthread_mutex_lock(&(helium_thread::mutex_thread));
pid_B = getpid();
cout<<"The pid value of Thread B is"<< pid_B << endl;
shared_variable = 5;
/** Now you put a sleep to introduce a race condition **/
/** You will find that there is no race condition here **/
//sleep(5);
cout<<"Signal the thread A now "<<endl;
pthread_cond_signal (&helium_thread::cond_var);
cout<<"Changed the shared_variable value now"<<endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout<<"Return thread function b now"<<endl;
}
int main(int argc, char *argv[])
{
pid_t thread_pid_val = getpid();
thread_1.create_thread((thread_1.get_thread_id()),NULL,Thread_Function_A,&thread_pid_val);
thread_2.create_thread((thread_2.get_thread_id()),NULL,Thread_Function_B,&thread_pid_val);
pthread_join( *(thread_1.get_thread_id()), NULL);
pthread_join( *(thread_2.get_thread_id()), NULL);
return 0;
}
在线程线程函数A和线程函数B中运行的两个函数有所不同 在Thread_Function_B中,首先要做的是获取锁,而在Thread_Function_A中,首先获取pid,然后启动while循环,然后获取锁 因此,当创建两个线程时,B 1st获得锁,A必须等待机会获得锁。B将共享变量的值设置为5,然后设置信号条件变量。尽管在本例中,到目前为止还没有线程处于等待状态(因为A尚未获得锁,然后处于等待状态) 当B释放锁A时,它发现共享变量为5,因此进入else状态 理想情况下,您希望第一次获得锁并等待条件,但在您当前的实现中,这并没有发生 尝试先在A中获取锁,然后继续
void *Thread_Function_A(void *thread_arg)
{
pthread_mutex_lock(&(helium_thread::mutex_thread));
//remaining logic
我消除了大部分代码混乱,并将日志语句修改得更清晰一些。我没有看到你所看到的
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
using namespace std;
int shared_variable = 7;
pid_t pid_A;
pid_t pid_B;
class helium_thread
{
private:
pthread_t *thread_id;
pid_t process_pid;
public:
static pthread_mutex_t mutex_thread;
static pthread_cond_t cond_var;
void set_thread_id(pthread_t tid);
pthread_t *get_thread_id();
int create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg );
helium_thread();
~helium_thread();
};
helium_thread thread_1, thread_2;
pthread_mutex_t helium_thread::mutex_thread = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t helium_thread::cond_var = PTHREAD_COND_INITIALIZER;
void helium_thread::set_thread_id( pthread_t tid) {*(this->thread_id) = tid;}
pthread_t * helium_thread::get_thread_id() {return (this->thread_id);}
int helium_thread::create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg )
{
int ret;
ret = pthread_create(thread_ptr, attr, start_routine, (void *)arg) ;
return ret;
}
helium_thread::helium_thread() {thread_id = new pthread_t; }
helium_thread::~helium_thread() {delete thread_id;}
void *Thread_Function_A(void *thread_arg)
{
while (1)
{
pthread_mutex_lock(&(helium_thread::mutex_thread));
cout << "TA lock acquired" << endl;
if ( shared_variable != 5)
{
cout << "TA Going to conditional wait" << endl;
pthread_cond_wait(&helium_thread::cond_var, &helium_thread::mutex_thread);
cout << "TA Sleep after cond_wait" << endl;
sleep(5);
cout << "TA The cond_wait is unblocked now " << endl;
cout << "TA The thread A proceeds" << endl;
cout << "TA The shared_variable value = " << shared_variable << endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout << "TA unlocked" << endl;
}
else
{
cout << "TA Else condition thread A..shared variable value is " << shared_variable << endl;
cout << "TA The condition of thread A is met now" << endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout << "TA unlocked in else condition" << endl;
pthread_exit(NULL);
}
}
return NULL;
}
void *Thread_Function_B(void *thread_arg)
{
pthread_mutex_lock(&(helium_thread::mutex_thread));
shared_variable = 5;
cout << "TB Signal the thread A now " << endl;
pthread_cond_signal (&helium_thread::cond_var);
cout << "TB the changed shared_variable is now" << endl;
pthread_mutex_unlock(&(helium_thread::mutex_thread));
cout << "TB Return thread now" << endl;
return NULL;
}
int main(int argc, char *argv[])
{
thread_1.create_thread((thread_1.get_thread_id()), NULL, Thread_Function_A, NULL);
thread_2.create_thread((thread_2.get_thread_id()), NULL, Thread_Function_B, NULL);
pthread_join( *(thread_1.get_thread_id()), NULL);
pthread_join( *(thread_2.get_thread_id()), NULL);
return 0;
}
两个
TA lock acquired
TA Going to conditional wait
TB Signal the thread A now
TB the changed shared_variable is now
TB Return thread now
TA Sleep after cond_wait
TA The cond_wait is unblocked now
TA The thread A proceeds
TA The shared_variable value = 5
TA unlocked
TA lock acquired
TA Else condition thread A..shared variable value is 5
TA The condition of thread A is met now
TA unlocked in else condition
三个
TA lock acquired
TA Going to conditional wait
TB Signal the thread A now
TB the changed shared_variable is now
TA Sleep after cond_wait
TB Return thread now
TA The cond_wait is unblocked now
TA The thread A proceeds
TA The shared_variable value = 5
TA unlocked
TA lock acquired
TA Else condition thread A..shared variable value is 5
TA The condition of thread A is met now
TA unlocked in else condition
TB Signal the thread A now
TB the changed shared_variable is now
TB Return thread now
TA lock acquired
TA Else condition thread A..shared variable value is 5
TA The condition of thread A is met now
TA unlocked in else condition
这是太多的代码。你的程序在哪里?另外,作为一条硬性规定:程序的正确性不应取决于处理器的速度(即:是否有睡眠调用)。测试也是如此——在行业中,我们对涉及睡眠的测试用例有一个词:“片状”。更喜欢回调驱动的测试,或者使用模拟(GoogleGmock)。API的设计使得编写愚蠢的bug变得更加困难。除了不必记住在每个对象上调用create和destroy函数外,您还可以使用锁保护来确保异常安全,一种形式的
条件变量::wait
被设计为使用lambda,这样就不可能忘记循环,从而确保正确性,在其他有用的设计引发的安全机制中,只要看看线程A和线程B的例程函数,其他代码就没有那么重要了。我试图理解为什么睡眠会导致忽略一些顺序执行。事实上,有些指令从未执行过,因为我从未得到指纹。为简单起见,只需查看以下函数-void*Thread\u Function\u A(void*Thread\u arg)和void*Thread\u Function\u B(void*Thread\u arg)。其他代码没有那么重要。根据输出,永远不会执行带有条件变量wait和sleep()
的分支。您可能希望在等待条件变量之前输出一些内容。我已经编辑了代码,您会发现在条件等待之前的调试打印实际上已经出现。这意味着它处于if状态。另外,如果我取消睡眠,这个问题就不会发生。我试图理解为什么睡眠在这里起着重要作用。你只要按原样运行我的代码,你就会看到区别。我去掉了很多指纹,我发现它的行为和你所展示的一样。但是,请按原样运行我的程序。你会看到区别的。谢谢!我想,我明白了。有一个问题-在这两个if(shared_variable!=5){/**如果我在这里从线程B获得信号**/这是在pthread_cond_wait**之前。我的信号会丢失吗。我看到它没有丢失,为什么会这样呢?pthread_cond_wait(&hemia_thread::cond_var,&hemia_thread::mutex_thread);或者更准确地说,如果我从线程B获得信号,那么您所描述的可能也确实会发生在写得不好的代码中。由于互斥锁的位置,这种情况不会发生在您的代码中。只有一个线程会有锁,或者发信号,或者等待。在释放锁之前,B线程会更改变量,因此即使在de中也是如此生成案例您的条件(if)跳过了等待。我不知道您这样做是出于设计还是运气,但这就是我看到的情况。
TB Signal the thread A now
TB the changed shared_variable is now
TB Return thread now
TA lock acquired
TA Else condition thread A..shared variable value is 5
TA The condition of thread A is met now
TA unlocked in else condition