Skip to content

Files

Latest commit

 

History

History
154 lines (116 loc) · 4.38 KB

84.md

File metadata and controls

154 lines (116 loc) · 4.38 KB

多线程编程:复习题

原文:https://github.com/angrave/SystemProgramming/wiki/Multi-threaded-Programming%3A-Review-Questions

警告 - 问题编号可能会有变化

Q1

以下代码是否是线程安全的?重新设计以下代码是线程安全的。提示:如果消息内存对每个调用都是唯一的,则不需要互斥锁。

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'函数返回其最低值的参数。

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

完成以下代码。以下代码应该打印交替AB。它代表两个轮流执行的线程。将条件变量调用添加到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;
}

Q5

确定给定代码中的关键部分。添加互斥锁定以使代码线程安全。添加条件变量调用,以使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;
}

Q6

非线程安全数据结构具有size() enqdeq方法。使用条件变量和互斥锁来完成线程安全的阻塞版本。

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(修改图形)。

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,但是当shortestset_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);
}