我在后端线程中使用libevent来运行hiredis并订阅远程redis数据库。订阅使用来自另一个SO问题的简单示例非常有效:
但是,为了避免竞争条件,从主线程添加订阅并非易事。为此,我创建了一个std::vector<std::string>
对象,其中包含后端应订阅的任何键字符串。通过互斥锁执行对此向量的读取。
但是,如何通知后端我添加了一些订阅?目前我使用的计时器设置为非常低的分辨率:
void Client::fireAndRequeueTimer(int fd, short e, void* arg)
{
Client* client = reinterpret_cast<Client*>(arg); // the client handles the subscription to redis (via hiredis/libevent)
if (client->mDisconnect)
return; // the main thread wants us to exit, so we don't recreate the timer
event* ev = &client->mTimerEvent; // some timer event object we created
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000; // 1ms
evtimer_add(ev, &tv);
// mPendingSubscriptions is an std::vector of strings, which contain the keys that we should add subscriptions to.
if (client->mPendingSubscriptions.size())
{
std::unique_lock<std::mutex> lock(client->mSubscriptionsMutex);
do
{
redisAsyncCommand(
client->mContext,
Client::subCallback,
(char*)"sub",
"SUBSCRIBE %s",
client->mPendingSubscriptions.back().c_str());
client->mPendingSubscriptions.pop_back();
}
while (client->mPendingSubscriptions.size());
}
}
(请注意,我正在使用libevent 1.4.x
,因此EV_PERSIST等功能不存在,我必须在每个事件中重新创建计时器。
虽然上述情况有效,但由于以下原因,我对此并不满意:
这个问题的解决方案是否会在libevent 1.4.x
的范围内解决这些问题?
答案 0 :(得分:1)
就个人而言,我更喜欢让目标线程在其事件队列中添加eventfd
(或类似的构造)。
可以安全地从任何其他线程通知eventfd
,并使目标线程调用关联的事件处理程序。
这样,您无需担心正确锁定libevent结构的绝对最小值,因为操作系统会为您解决这个问题。
注意: public class logInController : Controller
{
[HttpPost]
public ActionResult Index(logInModel model)
{
if(ModelState.IsValid)
{
int match = 0;
sqlConn = new SqlConnection(sqlConnString);
sqlComm = new SqlCommand("spLogin", sqlConn);
sqlComm.CommandType = CommandType.StoredProcedure;
sqlComm.Parameters.AddWithValue("@userName", model.Username);
sqlComm.Parameters.AddWithValue("@password", model.Password);
SqlParameter userMatch = new SqlParameter("@userMatch", SqlDbType.Int);
userMatch.Direction = ParameterDirection.Output;
sqlComm.Parameters.Add(userMatch);
sqlConn.Open();
sqlComm.ExecuteNonQuery();
match = Convert.ToInt32(sqlComm.Parameters["@userMatch"].Value);
sqlConn.Close();
if (match != 0)
{
FormsAuthentication.SetAuthCookie(model.Username, false);
return RedirectToAction("index","home");
}
else
ModelState.AddModelError("", "Invalid username or password");
}
return View();
}
}
在OSX上不可用,但只要您不需要极高的事件率,就可以使用管道轻松模拟。