如何防止此 pthread 同步内存踩踏?

How to prevent this pthread synchronization memory stomping?

以下程序,我在其中使用临界区来保护 writer/readers 模式:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define NAME_SIZE 6
#define NUM_THREADS 4
static char name[NAME_SIZE];
pthread_mutex_t mt;
pthread_cond_t read_phase;

void* name_joey(void *arg);
void* name_jimmy(void *arg);
void* name_leah(void *arg);
void* print_name(void *arg);


int main(void)
{
    pthread_t joey;
    pthread_t jimmy;
    pthread_t leah;
    pthread_t printer;

    pthread_create(&joey, NULL, name_joey, NULL);
    pthread_create(&jimmy, NULL, name_jimmy, NULL);
    pthread_create(&leah, NULL, name_leah, NULL);
    pthread_create(&printer, NULL, print_name, NULL);

    pthread_join(joey, NULL);
    pthread_join(jimmy, NULL);
    pthread_join(leah, NULL);
    pthread_join(printer, NULL);
    return EXIT_SUCCESS;
}

void* name_joey(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mt);
        memset(name, 0, NAME_SIZE);
        strcpy(name, "Joey[=10=]");
        pthread_mutex_unlock(&mt);
    }
    return 0;
}
void* name_jimmy(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mt);
        memset(name, 0, NAME_SIZE);
        strcpy(name, "Jimmy[=10=]");
        pthread_mutex_unlock(&mt);
    }
    return 0;
}
void* name_leah(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mt);
        memset(name, 0, NAME_SIZE);
        strcpy(name, "Leah[=10=]");
        pthread_mutex_unlock(&mt);
    }
    return 0;
}

void* print_name(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mt);
        printf("%s\n", name);
        pthread_mutex_unlock(&mt);
        sleep(1);
    }
    return 0;
}

生成此输出的变体:

Loey
Leah
Leah
Jimmy
Jimm
Joey
eah
Jimm
Jimmy
Loey
Leah
Loey
Jimmy
imm
Loey
Loeh
Jeey
Limm
Jimm
Jimmy
Leah
Leah
Jimmy
Jimmy
Jimm
Jeah
Loey
Jimmy
Jimmy
Jeah

这不是想要的效果。除了在每次写入之前将内存完全清零之外,我还为代码的每个 write/read 区域提供了关键部分。是什么导致内存像这样部分变形?

当 运行 您的代码时,我看到名称以不可预测的顺序打印,但我没有看到像您的输出所暗示的那样的错位。我在 Arch Linux.

上使用 glibc 2.29-3

编辑:我注意到您没有调用 pthread_mutex_init。顺便说一句,未初始化的(零)mt 在我的平台上似乎是可锁定的,但它可能会导致您在您的平台上看到的问题。我不确定当您调用 pthread_mutex_lock 时您的平台是否 return 发出错误代码,因为它未初始化,但最好检查这些调用的 return 值.

互斥量 mt 正在使用 un 初始化。因此,对 pthread_mutex_lock()pthread_mutex_unlock() 的调用可能无法按预期工作。如果代码检查后一个函数的 return 值,这将变得很明显,如下所示:

  if (0 != pthread_mutex_lock(&mt))
  {
    /* Handle and log error here. */
  }

可以按如下方式处理和记录错误:

  if (0 != (errno = pthread_mutex_lock(&mt)))  /* Needs errno.h. */
  {
    perror("pthread_mutex_lock() failed");  /* Requires errno to be set. */
    exit(EXIT_FAILURE);  /* Needs stdlib.h. */
  }

要在最简单的情况下初始化互斥锁,请执行以下操作:

pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;

或者:

  if (0 != pthread_mutex_init(&mt, NULL))
  {
    /* Handle and log error here. */
  }

related documentation is here.