【问题标题】:How to safely modify string from another thread in C with pthreads?如何使用 pthreads 从 C 中的另一个线程安全地修改字符串?
【发布时间】:2021-07-17 15:58:45
【问题描述】:

我正在尝试用 C 创建一个简单的 CLI 音乐播放器。除了负责播放音乐的主线程之外,我还创建了第二个线程。第二个线程接收这样的参数(我尝试过使用和不使用 volatile 关键字):

typedef struct AUDIO_S
{
    volatile char audio_path[MAX_PATH];
    volatile int play_state;
} audio_t;

主线程可能会更新音频路径(当前文件)和播放状态(播放/暂停)。第二个线程的工作是检测这种变化,并通过改变、播放或暂停歌曲来采取相应的行动。

我有一个问题,(我假设)正在发生的事情是第二个线程在读取此数据的同时由主线程写入,这会产生乱码输出。我尝试实现一个条件变量,但输出仍然很糟糕。

这是我写数据的代码:

extern pthread_mutex_t mutex;
extern pthread_cond_t cond;

pthread_mutex_lock(&mutex);

strcpy(audio->audio_path, state->cur_play_dir);
strcat(audio->audio_path, "/");
strcat(audio->audio_path, state->cur_play_file);
audio->play_state = MUSIC_PLAY;

pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

这是我读到的代码:

extern pthread_mutex_t mutex;
extern pthread_cond_t cond;

while (1)
{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond, &mutex);

    char *new_audio_path = audio->audio_path;
    if (strcmp(new_audio_path, cur_audio_path))
    {               
        cur_audio_path = realloc(cur_audio_path,
                                strlen(new_audio_path) + 1);

        strcpy(cur_audio_path, audio->audio_path);
        printw("PATH: %s\n", cur_audio_path);
    }

    pthread_mutex_unlock(&mutex);
}

互斥体和条件被声明为全局变量,如下所示:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

我对并行编程还很陌生,所以我怀疑我在做一些非常明显和愚蠢的事情。

【问题讨论】:

  • volatile 没有解决线程同步问题,不应在 C 中用于该目的。您似乎为此目的正确使用了互斥锁,因此,如果您提供了只访问有问题的数据,那么我认为你的不是同步问题。
  • 我确实注意到,在继续使用其结果之前,您未能测试 realloc() 是否成功。可能与您的问题有关。
  • 总的来说,我们可能需要minimal reproducible example 来提供很大帮助。
  • 我现在没有电脑,但一个不错的 YouTube 频道是 Jacob Sorber 频道。你可能想看看这个视频:youtu.be/9axu8CUvOKY我认为它可以帮助你。
  • 我的第一个猜测是,您还应该检查来自pthread_mutex_lock(&mutex); 的返回状态,因为它可能会失败。然而,这是一个非常微弱的概率。另一方面,您应该检查您是否在代码的两个部分中都使用了 same 互斥体实例。你如何共享互斥锁?作为公共库中的静态声明,还是仅在一个可执行文件中拥有“全部”?

标签: c multithreading pthreads race-condition


【解决方案1】:

在这个问题上睡觉后,我意识到我的错误。事实证明,存储在路径字符串中的数据实际上根本没有问题。

在第二个线程中,我打印到 stdout 的路径值纯粹是为了检查该值是否有效(所以我忘了锁定任何东西)。但是,在主线程中,我还将其他数据打印到标准输出。

两个线程都写入标准输出,打印时数据出现乱码,而实际上存储在内存中的数据没有问题。我通过在第一个线程写入标准输出时写入第二个线程中的文本文件来验证这一点。写入文本文件的数据没有问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 2016-07-27
    • 2010-09-22
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多