MST

星途 面试题库

面试题:C语言结构体作为函数参数在复杂场景下的传递选择

在一个多线程的C语言项目中,有一个结构体用于存储共享数据,不同的线程会调用不同的函数对该结构体进行读写操作。设计一个方案,选择合适的结构体作为函数参数的传递方式(传值、传指针或其他合理方式),确保在多线程环境下数据的一致性和高效访问。同时,需要考虑如何避免竞态条件,描述你所采用的同步机制,并分析该方案在不同平台(如Linux、Windows)上可能面临的兼容性问题及应对策略。
40.7万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

结构体参数传递方式

  1. 传指针:在多线程环境下,传指针是较为合适的方式。传值会在函数调用时复制整个结构体,这不仅浪费内存和时间,而且多个线程操作的是不同副本,无法共享数据,违背需求。而传指针能让不同线程操作同一个结构体实例,实现数据共享。例如:
#include <pthread.h>
#include <stdio.h>

// 定义共享数据结构体
typedef struct {
    int data;
    // 其他共享数据成员
} SharedData;

// 线程函数,接受共享数据结构体指针
void* thread_func(void* arg) {
    SharedData* shared = (SharedData*)arg;
    // 对共享数据进行操作
    shared->data++;
    return NULL;
}

int main() {
    pthread_t tid;
    SharedData shared = {0};
    pthread_create(&tid, NULL, thread_func, &shared);
    pthread_join(tid, NULL);
    printf("Final data: %d\n", shared.data);
    return 0;
}

避免竞态条件的同步机制

  1. 互斥锁(Mutex):在访问共享结构体数据前加锁,访问完后解锁。这确保同一时间只有一个线程能访问共享数据,避免竞态条件。例如在上述代码基础上添加互斥锁:
#include <pthread.h>
#include <stdio.h>

// 定义共享数据结构体
typedef struct {
    int data;
    // 其他共享数据成员
    pthread_mutex_t mutex;
} SharedData;

// 线程函数,接受共享数据结构体指针
void* thread_func(void* arg) {
    SharedData* shared = (SharedData*)arg;
    pthread_mutex_lock(&shared->mutex);
    // 对共享数据进行操作
    shared->data++;
    pthread_mutex_unlock(&shared->mutex);
    return NULL;
}

int main() {
    pthread_t tid;
    SharedData shared = {0, PTHREAD_MUTEX_INITIALIZER};
    pthread_create(&tid, NULL, thread_func, &shared);
    pthread_join(tid, NULL);
    pthread_mutex_destroy(&shared->mutex);
    printf("Final data: %d\n", shared.data);
    return 0;
}
  1. 读写锁(Read - Write Lock):如果读操作远多于写操作,使用读写锁更高效。读操作可以同时进行,写操作则需要独占锁。例如:
#include <pthread.h>
#include <stdio.h>

// 定义共享数据结构体
typedef struct {
    int data;
    // 其他共享数据成员
    pthread_rwlock_t rwlock;
} SharedData;

// 读线程函数,接受共享数据结构体指针
void* read_thread_func(void* arg) {
    SharedData* shared = (SharedData*)arg;
    pthread_rwlock_rdlock(&shared->rwlock);
    // 进行读操作
    printf("Read data: %d\n", shared->data);
    pthread_rwlock_unlock(&shared->rwlock);
    return NULL;
}

// 写线程函数,接受共享数据结构体指针
void* write_thread_func(void* arg) {
    SharedData* shared = (SharedData*)arg;
    pthread_rwlock_wrlock(&shared->rwlock);
    // 进行写操作
    shared->data++;
    pthread_rwlock_unlock(&shared->rwlock);
    return NULL;
}

int main() {
    pthread_t read_tid, write_tid;
    SharedData shared = {0, PTHREAD_RWLOCK_INITIALIZER};
    pthread_create(&read_tid, NULL, read_thread_func, &shared);
    pthread_create(&write_tid, NULL, write_thread_func, &shared);
    pthread_join(read_tid, NULL);
    pthread_join(write_tid, NULL);
    pthread_rwlock_destroy(&shared->rwlock);
    printf("Final data: %d\n", shared.data);
    return 0;
}

不同平台兼容性问题及应对策略

  1. Linux平台:Linux提供了丰富的POSIX线程库(pthread),上述使用互斥锁和读写锁的方案在Linux下能很好运行。但要注意在不同Linux内核版本下,线程库的性能和一些特性可能有微小差异,需参考官方文档确保代码兼容性。
  2. Windows平台:Windows没有POSIX线程库原生支持,可使用Windows API中的临界区(Critical Section)实现类似互斥锁功能,使用SRW锁实现类似读写锁功能。例如临界区使用:
#include <windows.h>
#include <stdio.h>

// 定义共享数据结构体
typedef struct {
    int data;
    // 其他共享数据成员
    CRITICAL_SECTION cs;
} SharedData;

// 线程函数,接受共享数据结构体指针
DWORD WINAPI thread_func(LPVOID arg) {
    SharedData* shared = (SharedData*)arg;
    EnterCriticalSection(&shared->cs);
    // 对共享数据进行操作
    shared->data++;
    LeaveCriticalSection(&shared->cs);
    return 0;
}

int main() {
    HANDLE tid;
    SharedData shared = {0};
    InitializeCriticalSection(&shared.cs);
    tid = CreateThread(NULL, 0, thread_func, &shared, 0, NULL);
    WaitForSingleObject(tid, INFINITE);
    DeleteCriticalSection(&shared.cs);
    printf("Final data: %d\n", shared.data);
    CloseHandle(tid);
    return 0;
}

为提高跨平台兼容性,可以使用跨平台库如Boost.Thread,它提供了统一的线程和同步原语接口,屏蔽了不同平台差异。在代码中引入Boost.Thread库后,可使用其提供的mutex和shared_mutex等同步工具,编写跨平台的多线程代码。