ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 多线程编程:复习题 > 原文:<https://github.com/angrave/SystemProgramming/wiki/Multi-threaded-Programming%3A-Review-Questions> > 警告 - 问题编号可能会有变化 ## Q1 以下代码是否是线程安全的?重新设计以下代码是线程安全的。提示:如果消息内存对每个调用都是唯一的,则不需要互斥锁。 ```c static char message[20]; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void format(int v) { pthread_mutex_lock(&mutex); sprintf(message, ":%d:" ,v); pthread_mutex_unlock(&mutex); return message; } ``` ## Q2 以下哪一项不会导致进程退出? * 从最后一个运行线程中的 pthread 的启动函数返回。 * 从 main 返回的原始线程。 * 任何导致分段错误的线程。 * 任何调用`exit`的线程。 * 在主线程中调用`pthread_exit`,其他线程仍在运行。 ## Q3 写下将由以下程序打印的“W”字符数的数学表达式。假设 a,b,c,d 是小的正整数。你的答案可能会使用'min'函数返回其最低值的参数。 ```c unsigned int a=...,b=...,c=...,d=...; void* func(void* ptr) { char m = * (char*)ptr; if(m == 'P') sem_post(s); if(m == 'W') sem_wait(s); putchar(m); return NULL; } int main(int argv, char** argc) { sem_init(s,0, a); while(b--) pthread_create(&tid, NULL, func, "W"); while(c--) pthread_create(&tid, NULL, func, "P"); while(d--) pthread_create(&tid, NULL, func, "W"); pthread_exit(NULL); /*Process will finish when all threads have exited */ } ``` ## Q4 完成以下代码。以下代码应该打印交替`A`和`B`。它代表两个轮流执行的线程。将条件变量调用添加到`func`,以便等待的线程不需要连续检查`turn`变量。问:是否需要 pthread_cond_broadcast 或者 pthread_cond_signal 是否足够? ```c pthread_cond_t cv = PTHREAD_COND_INITIALIZER; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; void* turn; void* func(void* mesg) { while(1) { // Add mutex lock and condition variable calls ... while(turn == mesg) { /* poll again ... Change me - This busy loop burns CPU time! */ } /* Do stuff on this thread */ puts( (char*) mesg); turn = mesg; } return 0; } int main(int argc, char** argv){ pthread_t tid1; pthread_create(&tid1, NULL, func, "A"); func("B"); // no need to create another thread - just use the main thread return 0; } ``` ## Q5 确定给定代码中的关键部分。添加互斥锁定以使代码线程安全。添加条件变量调用,以使`total`永远不会变为负数或高于 1000.相反,调用应该阻塞,直到可以继续进行。解释为什么`pthread_cond_broadcast`是必要的。 ```c int total; void add(int value) { if(value < 1) return; total += value; } void sub(int value) { if(value < 1) return; total -= value; } ``` ## Q6 非线程安全数据结构具有`size()` `enq`和`deq`方法。使用条件变量和互斥锁来完成线程安全的阻塞版本。 ```c void enqueue(void* data) { // should block if the size() would become greater than 256 enq(data); } void* dequeue() { // should block if size() is 0 return deq(); } ``` ## Q7 您的启动使用最新的交通信息提供路径规划。您的多付实习生创建了一个非线程安全的数据结构,其中包含两个函数:`shortest`(使用但不修改图形)和`set_edge`(修改图形)。 ```c graph_t* create_graph(char* filename); // called once // returns a new heap object that is the shortest path from vertex i to j path_t* shortest(graph_t* graph, int i, int j); // updates edge from vertex i to j void set_edge(graph_t* graph, int i, int j, double time); ``` 为了提高性能,多个线程必须能够同时调用`shortest`,但是当`shortest`或`set_edge`内​​没有其他线程执行时,只能通过一个线程修改图形。 使用互斥锁和条件变量来实现读写器解决方案。不完整的尝试如下所示。虽然这种尝试是线程安全的(因此足以用于演示日!),但它不允许多个线程同时计算`shortest`路径并且没有足够的吞吐量。 ```c path_t* shortest_safe(graph_t* graph, int i, int j) { pthread_mutex_lock(&m); path_t* path = shortest(graph, i, j); pthread_mutex_unlock(&m); return path; } void set_edge_safe(graph_t* graph, int i, int j, double dist) { pthread_mutex_lock(&m); set_edge(graph, i, j, dist); pthread_mutex_unlock(&m); } ```