【问题标题】:Are system calls thread-safe?系统调用是线程安全的吗?
【发布时间】:2020-06-26 04:34:31
【问题描述】:

我写了一个内核模块,它是一个类似于this Link的字符设备驱动程序。驱动程序的内部结构如下:

struct {
    str[500];
}channelData;

static channelData chData[4];

所以我有一个使用此驱动程序的多线程应用程序,我目前以下列方式使用此驱动程序:

typedef struct
{
        int channelId;
        int len;
        char arg[100];
} driverArgs;

class DevDrv{
    static void STR_READ(int channelId, char *data);
    static void STR_SEND(int channelId, char *data,int len);
};

void DevDrv::STR_READ(int channelId, char *data)
{
    driverArgs arg= {-1,0, {0}};
    arg.channelId = channelId;
    ioctl(mfilehandler,IOCTL_STR_READ,&arg);
    memcpy(data,arg.arg,arg.len)

}
void DevDrv::STR_SEND(int channelId, char *data,int len)
{
    driverArgs arg= {-1,0, {0}};
    arg.channelId = channelId;
    arg.len=len;
    memcpy(arg.arg,data,len);
    ioctl(mfilehandler,IOCTL_STR_SEND,&arg);
}

所以,问题是我的应用程序中的 4 个线程是否调用这些函数来读取或写入它们自己的 ChannelId 以读取或写入驱动程序:

thread1:
   DevDrv::STR_READ(0,&localdst);
thread2:
   DevDrv::STR_READ(1,&localdst);
thread3:
   DevDrv::STR_READ(2,&localdst);
thread4:
   DevDrv::STR_READ(3,&localdst);

是否发生了数据竞赛或类似的事情?

【问题讨论】:

标签: c++ c linux multithreading chardev


【解决方案1】:

不保证您的 channelData 结构是缓存对齐的,因此除非您明确同步 chData,否则您仍然会受到数据竞争的影响。

这是一场比赛的草图:

  1. 系统调用想要读入 CPU 0 上的通道 2。
  2. CPU 0 获取所有包含通道 2 的缓存行,这意味着:
    • 通道 2 中的所有字节
    • 距离通道 1 末尾的几个字节
    • 通道 3 开头的几个字节
  3. 读取照常进行。
  4. CPU 1 将 500 字节写入通道 1。
  5. 系统调用想要将 500 个字节读入 CPU 0 上的通道 1。
  6. CPU 0 从通道 1 中获取之前未获取的所有字节。
    • 通道 1 末尾的几个字节不会重新获取

在这种情况下,这几个字节在 CPU 0 上是陈旧的,因为它们被 CPU 1 覆盖,而 CPU 0 不知道。

它不知道,因为没有 memory barrier 告诉它它的缓存可能已经过时了。

现在,在许多情况下,系统调用会触发内存屏障,但不能保证。

您的用户空间程序很好,字符设备是与内核模块通信的规范方式,但您的内核模块必须正确同步。甚至您链接中的示例似乎也试图非常具有介绍性,并且在不使用原子的情况下执行 Device_Open++ 之类的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2015-04-18
    • 2011-10-07
    相关资源
    最近更新 更多