原文:https://github.com/angrave/SystemProgramming/wiki/Multi-threaded-Programming%3A-Review-Questions
警告 - 问题编号可能会有变化
以下代码是否是线程安全的?重新设计以下代码是线程安全的。提示:如果消息内存对每个调用都是唯一的,则不需要互斥锁。
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;
}
以下哪一项不会导致进程退出?
- 从最后一个运行线程中的 pthread 的启动函数返回。
- 从 main 返回的原始线程。
- 任何导致分段错误的线程。
- 任何调用
exit
的线程。 - 在主线程中调用
pthread_exit
,其他线程仍在运行。
写下将由以下程序打印的“W”字符数的数学表达式。假设 a,b,c,d 是小的正整数。你的答案可能会使用'min'函数返回其最低值的参数。
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 */
}
完成以下代码。以下代码应该打印交替A
和B
。它代表两个轮流执行的线程。将条件变量调用添加到func
,以便等待的线程不需要连续检查turn
变量。问:是否需要 pthread_cond_broadcast 或者 pthread_cond_signal 是否足够?
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;
}
确定给定代码中的关键部分。添加互斥锁定以使代码线程安全。添加条件变量调用,以使total
永远不会变为负数或高于 1000.相反,调用应该阻塞,直到可以继续进行。解释为什么pthread_cond_broadcast
是必要的。
int total;
void add(int value) {
if(value < 1) return;
total += value;
}
void sub(int value) {
if(value < 1) return;
total -= value;
}
非线程安全数据结构具有size()
enq
和deq
方法。使用条件变量和互斥锁来完成线程安全的阻塞版本。
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();
}
您的启动使用最新的交通信息提供路径规划。您的多付实习生创建了一个非线程安全的数据结构,其中包含两个函数:shortest
(使用但不修改图形)和set_edge
(修改图形)。
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
路径并且没有足够的吞吐量。
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);
}