【问题标题】:How to prevent this pthread synchronization memory stomping?如何防止这种 pthread 同步内存踩踏?
【发布时间】:2019-12-26 06:36:15
【问题描述】:

以下程序,我在其中使用临界区来保护写入者/读取者模式:

#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\0");
        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\0");
        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\0");
        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

这不是预期的效果。除了在每次写入之前完全清零内存之外,我还为代码的每个写入/读取区域提供了关键部分。是什么原因导致内存像这样部分畸形?

【问题讨论】:

    标签: c multithreading concurrency synchronization pthreads


    【解决方案1】:

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

      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

    【讨论】:

      【解决方案2】:

      在运行您的代码时,我看到以不可预知的顺序打印的名称,但我没有看到您的输出所暗示的混乱。我在 Arch Linux 上使用 glibc 2.29-3。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-04
        • 2015-07-09
        • 2014-01-02
        相关资源
        最近更新 更多