Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
pthread_mutex_unlock非原子_C_Multithreading_Winapi_Pthreads - Fatal编程技术网

pthread_mutex_unlock非原子

pthread_mutex_unlock非原子,c,multithreading,winapi,pthreads,C,Multithreading,Winapi,Pthreads,我有以下源代码(改编自我的原始代码): #包括“stdafx.h” #包括 #包括 #包括“pthread.h” #定义最大输入计数4 整数项=0; bool start=false; bool send_active=false; pthread\u mutex\u t mutex=pthread\u mutex\u初始值设定项; pthread_cond_t condNotEmpty=pthread_cond_初始值设定项; pthread_cond_t condNotFull=pthrea

我有以下源代码(改编自我的原始代码):

#包括“stdafx.h”
#包括
#包括
#包括“pthread.h”
#定义最大输入计数4
整数项=0;
bool start=false;
bool send_active=false;
pthread\u mutex\u t mutex=pthread\u mutex\u初始值设定项;
pthread_cond_t condNotEmpty=pthread_cond_初始值设定项;
pthread_cond_t condNotFull=pthread_cond_初始值设定项;
作废发送()
{ 
对于(;;){
如果(!开始)
继续;
开始=错误;
对于(int i=0;i<11;++i){
send_active=true;
pthread_mutex_lock(&mutex);
while(条目数==最大条目数)
pthread_cond_wait(&condNotFull,&mutex);
条目++;
pthread_cond_broadcast(&condNotEmpty);
pthread_mutex_unlock(&mutex);
send_active=false;
}
}
} 
void receive(){
对于(int i=0;i<11;++i){
pthread_mutex_lock(&mutex);
while(条目==0)
pthread_cond_wait(&condNotEmpty,&mutex);
条目--;
pthread_cond_广播(&condNotFull);
pthread_mutex_unlock(&mutex);
} 
如果(发送_活动)
printf(“x”);
} 
int _tmain(int argc,_TCHAR*argv[]
{
pthread_t s;
pthread_创建(&s,NULL,(void*(*)(void*))发送,NULL);
对于(;;){
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&condNotEmpty,NULL);
pthread_cond_init(&condNotFull,NULL);
开始=真;
接收();
pthread_mutex_destroy(&mutex);
互斥=空;
pthread_cond_destroy(&condNotEmpty);
pthread_cond_destroy(&condNotFull);
condNotEmpty=NULL;
condNotFull=NULL;
printf(“.”);
}
返回0;
}
问题如下:有时,在接收方法继续之前,发送函数中的最后一次解锁没有完成。在我的原始代码中,互斥体位于一个对象中,该对象在完成该工作后被删除。如果发送方法尚未完成最后一次解锁,则互斥锁无效,并且我的程序导致解锁失败

通过运行该程序可以很容易地再现该行为:每次显示“x”时,接收方法几乎完成,发送方法在解锁调用中“挂起”

我使用VS2008和VS2010进行了编译-两个结果都是相同的

pthread_mutex_unlock不是原子的,这将解决问题。我如何解决这个问题?欢迎任何意见

致意

迈克尔

你的printf(“x”)是一个教科书式的比赛条件示例

在pthread_mutex_unlock()之后,OS可以自由地在任何时间内不安排此线程:滴答、秒或天。您不能假设send\u active会在时间上被“伪造”。

pthread\u mutex\u unlock()必须根据定义在返回前释放该互斥体。释放互斥体的那一刻,就可以安排另一个争夺互斥体的线程。请注意,即使
pthread\u mutex\u unlock()
可以安排在互斥对象返回后才释放互斥对象(我认为您的意思是它是原子的),仍然会有一个与您现在看到的内容等效的争用条件(我不清楚您看到的是什么种族,因为一条评论表明您对访问
send\u active
以控制
printf()
调用的种族条件并不感兴趣)


在这种情况下,可以在调用它的函数中的
pthread\u mutex\u unlock()
和以下语句/表达式的“行之间”调度另一个线程-您将具有相同的竞争条件。

下面是一些关于可能发生的情况的推测。此分析中有几个注意事项:

  • 这是基于这样一种假设,即您使用的是来自的Win32 pthreads包
  • 这只是基于对该站点上pthreads源代码的非常简短的检查以及这里的问题和评论中的信息——我还没有机会实际运行/调试任何代码
调用
pthread\u mutex\u unlock()
时,它会减少锁计数,如果锁计数降至零,则会在关联的事件对象上调用Win32
SetEvent()
API,以允许任何等待互斥锁的线程解锁。非常标准的东西

这就是推测的原因。假设调用了
SetEvent()
来解除对等待互斥锁的线程的阻止,它会发出与给定句柄相关联的事件的信号(应该如此)。但是,在
SetEvent()之前
函数执行任何其他操作时,另一个线程开始运行并关闭调用该特定
SetEvent()
的事件对象句柄(通过调用
pthread\u mutex\u destroy()

现在,
SetEvent()
正在进行的调用有一个句柄值不再有效。我想不出有什么特别的原因,
SetEvent()
在发出事件信号后会对该句柄做任何事情,但可能会这样做(我还可以想象有人提出一个合理的论点,
SetEvent()
应该能够预期事件对象句柄在API调用期间保持有效)

如果这就是发生在您身上的情况(这是一个很大的如果),我不确定是否有一个简单的修复方法。我认为pthreads库必须进行更改,以便在调用
SetEvent()
之前复制事件句柄,然后在调用
SetEvent()时关闭该副本
返回调用。这样,即使“主”句柄被另一个线程关闭,句柄仍将保持有效。我猜它必须在许多地方执行此操作。这可以通过将受影响的Win32 API调用替换为对执行“复制句柄/call API/close duplicate”se的包装函数的调用来实现
#include "stdafx.h"
#include <stdlib.h> 
#include <stdio.h> 

#include "pthread.h"

#define MAX_ENTRY_COUNT 4  

int  entries = 0;  
bool start = false;

bool send_active = false;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
pthread_cond_t condNotEmpty = PTHREAD_COND_INITIALIZER;  
pthread_cond_t condNotFull = PTHREAD_COND_INITIALIZER;  

void send()
{ 
    for (;;) {
        if (!start)
            continue;
        start = false;

        for(int i = 0; i < 11; ++i) { 
            send_active = true;

            pthread_mutex_lock(&mutex); 
            while(entries == MAX_ENTRY_COUNT) 
                pthread_cond_wait(&condNotFull, &mutex);      
            entries++; 
            pthread_cond_broadcast(&condNotEmpty); 
            pthread_mutex_unlock(&mutex);

            send_active = false;
        }
    }
} 

void receive(){ 
    for(int i = 0; i < 11; ++i){ 
        pthread_mutex_lock(&mutex);  
        while(entries == 0) 
            pthread_cond_wait(&condNotEmpty, &mutex); 
        entries--;  
        pthread_cond_broadcast(&condNotFull);  
        pthread_mutex_unlock(&mutex);
    } 

    if (send_active)
        printf("x");
} 

int _tmain(int argc, _TCHAR* argv[])
{
    pthread_t s; 

    pthread_create(&s, NULL, (void *(*)(void*))send, NULL);  

    for (;;) {
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&condNotEmpty, NULL);
        pthread_cond_init(&condNotFull, NULL);

        start = true;

        receive();

        pthread_mutex_destroy(&mutex);
        mutex = NULL;
        pthread_cond_destroy(&condNotEmpty);
        pthread_cond_destroy(&condNotFull);
        condNotEmpty = NULL;
        condNotFull = NULL;

        printf(".");
    }

    return 0;
}
/*
 * FIXME!!!
 * The mutex isn't held by another thread but we could still
 * be too late invalidating the mutex below since another thread
 * may already have entered mutex_lock and the check for a valid
 * *mutex != NULL.
 *
 * Note that this would be an unusual situation because it is not
 * common that mutexes are destroyed while they are still in
 * use by other threads.
*/