readMVar不会在putMVar上唤醒

时间:2019-01-10 00:24:08

标签: multithreading haskell ghc

在另一个线程调用readMVar之后,我的代码似乎挂在putMVar上。我不希望发生这种情况,但这就是我所观察到的。我的主线程创建了两个新线程,每个线程都可以访问共享的MVar m。

线程1:

do
  putStrLn "tick"
  x <- readMVar m
  putStrLn "tock"

线程2:

do
  putMVar m 0
  putStrLn "put m0"
  void $ tryTakeMVar m
  putStrLn "take m"
  putMVar m 1
  putStrLn "put m1"

主要:

do
  m <- newEmptyMVar
  <start thread 1>
  <start thread 2>

在以下情况下,我的程序挂起:

两个线程可以访问共享的MVar m,该MVar最初为空。 readMVar m上的线程1块。同时,线程2调用putMVar m ...。此时,线程1 可以继续进行,但让我们假设它没有。然后,线程2调用tryTakeMVar m,大概清空了整个MVar。然后线程2再次调用putMVar m ...。这种情况对应于以下输出:

tick
put m0
take m
put m1
<hang>

这是怎么回事?我希望应该打印“ tock”,因为线程2充满了MVar,但是我的程序只是挂起了。

1 个答案:

答案 0 :(得分:5)

我在尝试调试空间泄漏时将MVar实现从 function addstudent() { var firstname = $("#firstname").val(); var lastname = $("#lastname").val(); var imageuploaded = $("#imageupload")[0].files[0]; var rememberme = $("#rememberme").is(":checked"); var newsletter = $("#newsletter").is(":checked"); var gender = $("input[name=gender]:checked").val(); var studentDetails = new FormData(); studentDetails.append("FirstName", firstname); studentDetails.append("LastName", lastname); studentDetails.append("ImageUploaded", imageuploaded); studentDetails.append("RememberMe", rememberme); studentDetails.append("IsSubscribed", newsletter); studentDetails.append("Gender", gender); $.ajax({ url: "/Student/InsertStudent", type:"POST", dataType: "json", contentType: false, processData: false, data: studentDetails, success: onsuccessinsert, error:onerrorinsert }); return false; } 切换到<form class="form-horizontal" id="studentform" autocomplete="off"> <input type="hidden" id="hiddenid" /> <div class="form-group"> <label for="firstname" class="col-sm-2 control-label"> Name</label> <div class="col-sm-10"> <input type="text" class="form-control" id="firstname" name="firstname" placeholder="Enter First Name"/> </div> </div> <div class="form-group"> <label for="lastname" class="col-sm-2 control-label">Last Name</label> <div class="col-sm-10"> <input type="text" class="form-control" id="lastname" placeholder="Enter Last Name"/> </div> </div> <div class="form-group"> <label for="imageinput" class="col-sm-2 control-label">Image Upload</label> <div class="col-sm-10"> <input type="file" class="form-control-file" id="imageupload" placeholder="Please Select a Image" accept="image/jpeg,image/jpg,image/gif,image/png,image/bmp" /> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="checkbox"> <label><input type="checkbox" id="rememberme" value="true" > Remember me</label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="checkbox"> <label><input type="checkbox" id="newsletter"> Subscribed To Newsletter</label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="radio"> <label><input type="radio" name="gender" value="male" id="gender1" /> Male</label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <div class="radio"> <label><input type="radio" name="gender" value="female" id="gender2" /> Female</label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-success" onclick="addstudent()" id="insertbtn">Sign in</button> </div> </div> 。但是正如问题所表明的那样,我的代码使用了 public JsonResult InsertStudent(StudentDetails studentDetails) { try { string filename = Guid.NewGuid() + studentDetails.ImageUploaded.FileName; string imagefullpath = Server.MapPath(@"~\ImageUploaded\") + filename; string imageshortpath = @"WebApplication1\ImageUploaded\" + filename; studentDetails.ImageFullUrl = imagefullpath; studentDetails.ImageShortUrl = imageshortpath; studentDetails.ImageName = filename; studentDetails.ImageUploaded.SaveAs(imagefullpath); return Json(dbcontextStudentDetails.insertstudent(studentDetails), JsonRequestBehavior.AllowGet); } catch (Exception message) { return Json(message); } } ,由于某些原因,base没有提供。因此,前阵子,我像这样实现strict-concurrency

tryReadMVar

没有真正考虑其含义。从那以后,我就忘记了所有要做的事情。正如Daniel所指出的,旧版本的strict-concurrency曾经做过类似的事情,但是新版本具有原子的tryReadMVar实现。因此,即使我使用的是新版本的GHC,由于使用了tryReadMVar :: (NFData a) => MVar a -> IO (Maybe a) tryReadMVar m = do mm <- tryTakeMVar m case mm of Nothing -> return () Just a -> putMVar m a return mm ,该问题仍然被重新引入。

同时,死锁在以下情况下发生(丹尼尔描述):

  • 线程1打印“刻度”
  • 线程2使用base
  • 放置mvar
  • 线程2打印“ put m0”
  • 线程1在tryReadMVar中使用strict-concurrency获取mvar。
  • 线程2使用putMVar
  • 获取mvar
  • thread2打印“ take m”
  • thread2使用tryTakeMVar
  • 放置mvar
  • thread2打印“ put m1”
  • tryReadMVar内尝试tryTakeMVar时线程1死锁

事实证明,拥有原子putMVar很有用!