MIT6.828 Homework6:Threads and Locking

实验任务:

Insert lock and unlock statements in put and get so that the number of keys missing is always 0.

在put和get函数中插入lock和unlock语句,以便丢失的密钥数始终为0。

实验内容:

未插入lock和unlock语句时

$ gcc -g -O2 ph.c -pthread

$ ./a.out 2

运行命令得到以下结果

每个线程分两个阶段运行。在第一阶段,每个线程将NKEYS/nthread键放入哈希表中。在第二阶段,每个线程从哈希表中获取NKEYS。

$ ./a.out 1

再运行命令

可以看出,单线程与双线程完成时间大概相同,但是双线程做了两次get keys操作有效实现了并行;双线程会发生keys missing的情况。

查看代码分析出put key时调用insert函数时,会将新的entry插入到链表的头部,即修改链表头部指针,导致错误。

put和get中插入lock和unlock语句如下

pthread_mutex_t lock;     // declare a lock

// pthread_mutex_init(&lock, NULL);   // initialize the lock

// pthread_mutex_lock(&lock);  // acquire lock

// pthread_mutex_unlock(&lock);  // release lock

static

void put(int key, int value)

{

  pthread_mutex_lock(&lock);  // acquire lock

  int i = key % NBUCKET;

  insert(key, value, &table[i], table[i]);

  pthread_mutex_unlock(&lock);  // release lock

}

static struct entry*

get(int key)

{

  //pthread_mutex_lock(&lock);  // acquire lock

  struct entry *e = 0;

  for (e = table[key % NBUCKET]; e != 0; e = e->next) {

    if (e->key == key) break;

  }

  //pthread_mutex_unlock(&lock);  // release lock

  return e;

}

再次进行测试

可以看到双线程key不再丢失,代码正确,但是完成时间变长了。

再次查看get部分代码,发现get操作并未涉及到修改hash表,即

只有读取操作,所以可以不用进行锁保护,所以我们取消get部分的锁,再次运行:

static struct entry*

get(int key)

{

  // pthread_mutex_lock(&lock);  // acquire lock

  struct entry *e = 0;

  for (e = table[key % NBUCKET]; e != 0; e = e->next) {

    if (e->key == key) break;

  }

  // pthread_mutex_unlock(&lock);  // release lock

  return e;

}

可以看到双线程仍然可以正确运行,且完成时间缩短。

再尝试对put中每一个bucket上锁,仍能正确运行。

pthread_mutex_t lock[NBUCKET];

static

void put(int key, int value)

{

  int i = key % NBUCKET;

  pthread_mutex_lock(&lock[i]);

  insert(key, value, &table[i], table[i]);

  pthread_mutex_unlock(&lock[i]);

}

此时每个bucket都有一个互斥锁,当执行put操作时,首先获取待处理bucket的锁,然后在完成后释放锁。 这允许同时访问不同的bucket而不会相互冲突,可以使put操作在保持正确性的同时并行运行。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下问题如何修改jakarta.servlet.ServletException: 类text.HandlePassword不是Servlet org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Thread.java:748) 根本原因。 java.lang.ClassCastException: text.HandlePassword cannot be cast to jakarta.servlet.Servlet org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Thread.java:748)
06-08

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值