libevent reference Mannual II--library
FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html
The Libevent Reference Manual: Preliminaries
Libevent is a library for writing fast portable nonblocking IO. Its design goals are:
- portability
- speed
- scalability
- convenience
The components of Libevent:
- evutil: Generic functionality to abstract out the differences between different platforms' networking implementations.
- event and event_base: heart of libevent. diversity abstrct API, event-based nonblocking IO backends. It can let you know when sockets are ready to read or write, do basic timeout functionality, and detect OS signals.
- bufferevent: These functions provide a more convenient wrapper around Libevent’s event-based core. They let your application request buffered reads and writes, and rather than informing you when sockets are ready to do, they let you know when IO has actually occurred.
- evbuffer: This module implements the buffers underlying bufferevents, and provides functions for efficient and/or convenient access.
- evhttp: A simple HTTP client/server implementation.
- evdns: A simple DNS client/server implementation
- evrpc: A simple RPC implementation
Log messages in Libevent
Log internal errors and warnings, debugging messages (if support).
Default, these messages are written to stderr. could be overrided.
#define EVENT_LOG_DEBUG 0
#define EVENT_LOG_MSG 1
#define EVENT_LOG_WARN 2
#define EVENT_LOG_ERR 3 /* Deprecated; see note at the end of this section */
#define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG
#define _EVENT_LOG_MSG EVENT_LOG_MSG
#define _EVENT_LOG_WARN EVENT_LOG_WARN
#define _EVENT_LOG_ERR EVENT_LOG_ERR typedef void (*event_log_cb)(int severity, const char *msg); void event_set_log_callback(event_log_cb cb);
severity is one of EVENT_LOG_DEBUG, EVENT_LOG_MSG, EVENT_LOG_WARN, EVENT_LOG_ERR.
To override Libevent’s logging behavior, write your own function matching the signature of event_log_cb, and pass it as an argument to event_set_log_callback(). Whenever Libevent wants to log a message, it will pass it to the function you provided. You can have Libevent return to its default behavior by calling event_set_log_callback() again with NULL as an argument.
Handling fatal errors
Default behavior is to call exit() or abort() to leave current running process.
Interface
typedef void (*event_fatal_cb)(int err);
void event_set_fatal_callback(event_fatal_cb cb);
To set the event_set_fatal_callback(), later, if Libevent encounters a fatal error, the function you provided will be called.
PS: 1. should not return control to Libevent (cause undefined behavior); 2. the Libevent might exit anyway to avoid crashing; 3. any other Libevent function cannot be called.
Memory management
Default: Libevent uses the C library's memory management functions to allocate memory from the heap.
Libevent use another memory manager by providing your own replacements for malloc, realloc, and free.
Or if you have an instrumented allocator that you want Libevent to use in order to look for memory leaks.
Interface
void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
void *(*realloc_fn)(void *ptr, size_t sz),
void (*free_fn)(void *ptr));
Simple example
#include <event2/event.h>
#include <sys/types.h>
#include <stdlib.h> /* This union's purpose is to be as big as the largest of all the
* types it contains. */
union alignment {
size_t sz;
void *ptr;
double dbl;
};
/* We need to make sure that everything we return is on the right
alignment to hold anything, including a double. */
#define ALIGNMENT sizeof(union alignment) /* We need to do this cast-to-char* trick on our pointers to adjust
them; doing arithmetic on a void* is not standard. */
#define OUTPTR(ptr) (((char*)ptr)+ALIGNMENT)
#define INPTR(ptr) (((char*)ptr)-ALIGNMENT) static size_t total_allocated = ;
static void *replacement_malloc(size_t sz)
{
void *chunk = malloc(sz + ALIGNMENT);
if (!chunk) return chunk;
total_allocated += sz;
*(size_t*)chunk = sz;
return OUTPTR(chunk);
}
static void *replacement_realloc(void *ptr, size_t sz)
{
size_t old_size = ;
if (ptr) {
ptr = INPTR(ptr);
old_size = *(size_t*)ptr;
}
ptr = realloc(ptr, sz + ALIGNMENT);
if (!ptr)
return NULL;
*(size_t*)ptr = sz;
total_allocated = total_allocated - old_size + sz;
return OUTPTR(ptr);
}
static void replacement_free(void *ptr)
{
ptr = INPTR(ptr);
total_allocated -= *(size_t*)ptr;
free(ptr);
}
void start_counting_bytes(void)
{
event_set_mem_functions(replacement_malloc,
replacement_realloc,
replacement_free);
}
Locks and threading
Libevent structures can generally work three ways with multithreading.
Some structures are inherently single-threaded: it is never safe to use them from more than one thread at the same time.
Some structures are optionally locked: you can tell Libevent for each object whether you need to use it from multiple threads at once.
Some structures are always locked: if Libevent is running with lock support, then they are always safe to use from multiple threads at once.
Interface
#ifdef WIN32
int evthread_use_windows_threads(void);
#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
#endif
#ifdef _EVENT_HAVE_PTHREADS
int evthread_use_pthreads(void);
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED
#endif
Both functions return 0 on success, and -1 on failure.
If you need to use a different threading library, then you have a little more work ahead of you. You need to define functions that use your library to implement:
Locks
locking
unlocking
lock allocation
lock destruction
Conditions
condition variable creation
condition variable destruction
waiting on a condition variable
signaling/broadcasting to a condition variable
Threads
thread ID detection
Then you tell Libevent about these functions, using the evthread_set_lock_callbacks and evthread_set_id_callback interfaces.
Interface
#define EVTHREAD_WRITE 0x04
#define EVTHREAD_READ 0x08
#define EVTHREAD_TRY 0x10 #define EVTHREAD_LOCKTYPE_RECURSIVE 1
#define EVTHREAD_LOCKTYPE_READWRITE 2 #define EVTHREAD_LOCK_API_VERSION 1 struct evthread_lock_callbacks {
int lock_api_version;
unsigned supported_locktypes;
void *(*alloc)(unsigned locktype);
void (*free)(void *lock, unsigned locktype);
int (*lock)(unsigned mode, void *lock);
int (*unlock)(unsigned mode, void *lock);
}; int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *); void evthread_set_id_callback(unsigned long (*id_fn)(void)); struct evthread_condition_callbacks {
int condition_api_version;
void *(*alloc_condition)(unsigned condtype);
void (*free_condition)(void *cond);
int (*signal_condition)(void *cond, int broadcast);
int (*wait_condition)(void *cond, void *lock,
const struct timeval *timeout);
}; int evthread_set_condition_callbacks(
const struct evthread_condition_callbacks *);
For the version, struct evthread_lock_callbacks, described above,
lock_api_version is set as EVTHREAD_LOCK_API_VERSION,
supported_locktypes is set as EVTHREAD_LOCKTYPE_*,
alloc function must return a new lock of the specified type,
free function must release all resources held by a lock of the specified type,
lock function must try to acquire the lock in the specified mode, returning on success and nonzero on failure,
unlock function must try to unlock the lock, returning on success and nonzero on failure.
supported_locktypes modes are:
- 0
-
A regular, not-necessarily recursive lock.
- EVTHREAD_READ
-
For READWRITE locks only: acquire or release the lock for reading.
- EVTHREAD_WRITE
-
For READWRITE locks only: acquire or release the lock for writing.
- EVTHREAD_TRY
-
For locking only: acquire the lock only if the lock can be acquired immediately.
id_fn must be a function returning an unsigned long identifying what thread is calling the function. It must always return the same number for the same thread, and must not ever return the same number for two different threads if they are both executing at the same time.
The evthread_condition_callbacks structure describes callbacks related to condition variables.
lock_api_version field must be set to EVTHREAD_CONDITION_API_VERSION.
alloc_condition function must return a pointer to a new condition variable. It receives 0 as its argument.
free_condition function must release storage and resources held by a condition variable.
wait_condition function takes three arguments: a condition allocated by alloc_condition, a lock allocated by the evthread_lock_callbacks.alloc function you provided, and an optional timeout.
The lock will be held whenever the function is called; the function must release the lock, and wait until the condition becomes signalled or until the (optional) timeout has elapsed. The wait_condition function should return -1 on an error, 0 if the condition is signalled, and 1 on a timeout.
Before it returns, it should make sure it holds the lock again. Finally, the signal_condition function should cause one thread waiting on the condition to wake up (if its broadcast argument is false) and all threads currently waiting on the condition to wake up (if its broadcast argument is true). It will only be held while holding the lock associated with the condition.
Freeing global Libevent structures
Even when you’ve freed all the objects that you allocated with Libevent, there will be a few globally allocated structures left over. This isn’t usually a problem: once the process exits, they will all get cleaned up anyway.
void libevent_global_shutdown(void);
Calling libevent_global_shutdown() will make other Libevent functions behave unpredictably; don’t call it except as the last Libevent function your program invokes.
Creating an event_base
If an event_base is set up to use locking, it is safe to access it between multiple threads. Its loop can only be run in a single thread, however. If you want to have multiple threads polling for IO, you need to have an event_base for each thread.
Each event_base has a "method", or a backend that it uses to determine which events are ready. The recognized methods are:
select
poll
epoll
kqueue
devpoll
evport
win32
Setting up a default event_base
Interface
struct event_base *event_base_new(void);
Rerturn a pointer to a new event_base with the default settings when success, NULL the other way.
When choosing among methods, it picks the fastest method that the OS supports.
Setting up a complicated event_base
If you want more control over what kind of event_base you get, you need to use an event_config. An event_config is an opaque structure that holds information about your preferences for an event_base. When you want an event_base, you pass the event_config to event_base_new_with_config().
struct event_config *event_config_new(void);
struct event_base *event_base_new_with_config(const struct event_config *cfg);
void event_config_free(struct event_config *cfg);
To allocate an event_base with these functions, you call event_config_new() to allocate a new event_config. Then, you call other functions on the event_config to tell it about your needs. Finally, you call event_base_new_with_config() to get a new event_base. When you are done, you can free the event_config with event_config_free().
int event_config_avoid_method(struct event_config *cfg, const char *method); enum event_method_feature {
EV_FEATURE_ET = 0x01,
EV_FEATURE_O1 = 0x02,
EV_FEATURE_FDS = 0x04,
};
int event_config_require_features(struct event_config *cfg,
enum event_method_feature feature); enum event_base_config_flag {
EVENT_BASE_FLAG_NOLOCK = 0x01,
EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
int event_config_set_flag(struct event_config *cfg,
enum event_base_config_flag flag);
Calling event_config_avoid_method tells Libevent to avoid a specific available backend by name.
Calling event_config_require_feature() tells Libevent not to use any backend that cannot supply all of a set of features.
Calling event_config_set_flag() tells Libevent to set one or more of the run-time flags below when constructing the event base.
The recognized feature values for event_config_require_features are:
- EV_FEATURE_ET
-
Requires a backend method that supports edge-triggered IO.
- EV_FEATURE_O1
-
Requires a backend method where adding or deleting a single event, or having a single event become active, is an O(1) operation.
- EV_FEATURE_FDS
-
Requires a backend method that can support arbitrary file descriptor types, and not just sockets.
The recognized option values for event_config_set_flag() are:
- EVENT_BASE_FLAG_NOLOCK
-
Do not allocate locks for the event_base. Setting this option may save a little time for locking and releasing the event_base, but will make it unsafe and nonfunctional to access it from multiple threads.
- EVENT_BASE_FLAG_IGNORE_ENV
-
Do not check the EVENT_* environment variables when picking which backend method to use. Think hard before using this flag: it can make it harder for users to debug the interactions between your program and Libevent.
- EVENT_BASE_FLAG_STARTUP_IOCP
-
On Windows only, this flag makes Libevent enable any necessary IOCP dispatch logic on startup, rather than on-demand.
- EVENT_BASE_FLAG_NO_CACHE_TIME
-
Instead of checking the current time every time the event loop is ready to run timeout callbacks, check it after every timeout callback. This can use more CPU than you necessarily intended, so watch out!
- EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST
-
Tells Libevent that, if it decides to use the epoll backend, it is safe to use the faster "changelist"-based backend. The epoll-changelist backend can avoid needless system calls in cases where the same fd has its status modified more than once between calls to the backend’s dispatch function, but it also trigger a kernel bug that causes erroneous results if you give Libevent any fds cloned by dup() or its variants. This flag has no effect if you use a backend other than epoll. You can also turn on the epoll-changelist option by setting the EVENT_EPOLL_USE_CHANGELIST environment variable.
- EVENT_BASE_FLAG_PRECISE_TIMER
-
By default, Libevent tries to use the fastest available timing mechanism that the operating system provides. If there is a slower timing mechanism that provides more fine-grained timing precision, this flag tells Libevent to use that timing mechanism instead. If the operating system provides no such slower-but-more-precise mechanism, this flag has no effect.
The above functions that manipulate an event_config all return 0 on success, -1 on failure.
Interface
int event_config_set_max_dispatch_interval(struct event_config *cfg,
const struct timeval *max_interval, int max_callbacks,
int min_priority);
This function prevents priority inversion by limiting how many low-priority event callbacks can be invoked before checking for more high-priority events. If max_interval is non-null, the event loop checks the time after each callback, and re-scans for high-priority events if max_interval has passed. If max_callbacks is nonnegative, the event loop also checks for more events after max_callbacks callbacks have been invoked. These rules apply to any event of min_priority or higher.
Example: Preferring edge-triggered backends
struct event_config *cfg;
struct event_base *base;
int i; /* My program wants to use edge-triggered events if at all possible. So
I'll try to get a base twice: Once insisting on edge-triggered IO, and
once not. */
for (i=; i<; ++i) {
cfg = event_config_new(); /* I don't like select. */
event_config_avoid_method(cfg, "select"); if (i == 0)
event_config_require_features(cfg, EV_FEATURE_ET); base = event_base_new_with_config(cfg);
event_config_free(cfg);
if (base)
break; /* If we get here, event_base_new_with_config() returned NULL. If
this is the first time around the loop, we'll try again without
setting EV_FEATURE_ET. If this is the second time around the
loop, we'll give up. */
}
Example: Avoiding priority-inversion
struct event_config *cfg;
struct event_base *base; cfg = event_config_new();
if (!cfg)
/* Handle error */; /* I'm going to have events running at two priorities. I expect that
some of my priority-1 events are going to have pretty slow callbacks,
so I don't want more than 100 msec to elapse (or 5 callbacks) before
checking for priority-0 events. */
struct timeval msec_100 = { , * };
event_config_set_max_dispatch_interval(cfg, &msec_100, , ); base = event_base_new_with_config(cfg);
if (!base)
/* Handle error */; event_base_priority_init(base, );
Examining an event_base’s backend method
Sometimes you want to see which features are actually available in an event_base, or which method it’s using.
Interface
const char **event_get_supported_methods(void);
The event_get_supported_methods() function returns a pointer to an array of the names of the methods supported in this version of Libevent. The last element in the array is NULL.
const char *event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base *base);
The event_base_get_method() call returns the name of the actual method in use by an event_base. The event_base_get_features() call returns a bitmask of the features that it supports.
Example
struct event_base *base;
enum event_method_feature f; base = event_base_new();
if (!base) {
puts("Couldn't get an event_base!");
} else {
printf("Using Libevent with backend method %s.",
event_base_get_method(base));
f = event_base_get_features(base);
if ((f & EV_FEATURE_ET))
printf(" Edge-triggered events are supported.");
if ((f & EV_FEATURE_O1))
printf(" O(1) event notification is supported.");
if ((f & EV_FEATURE_FDS))
printf(" All FD types are supported.");
puts("");
}
Deallocating an event_base
void event_base_free(struct event_base *base);
Note that this function does not deallocate any of the events that are currently associated with the event_base, or close any of their sockets, or free any of their pointers.
Setting priorities on an event_base
int event_base_priority_init(struct event_base *base, int n_priorities);
This function returns 0 on success and -1 on failure. There is a constant, EVENT_MAX_PRIORITIES, that sets the upper bound on the value of n_priorities. It is an error to call this function with a higher value for n_priorities.
int event_base_get_npriorities(struct event_base *base);
The return value is equal to the number of priorities configured in the base. So if event_base_get_npriorities() returns 3, then allowable priority values are 0, 1, and 2.
Reinitializing an event_base after fork()
Not all event backends persist cleanly after a call to fork(). Thus, if your program uses fork() or a related system call in order to start a new process, and you want to continue using an event_base after you have forked, you may need to reinitialize it.
Interface
int event_reinit(struct event_base *base);
Obsolete event_base functions
Older versions of Libevent relied pretty heavily on the idea of a "current" event_base. The "current" event_base was a global setting shared across all threads. If you forgot to specify which event_base you wanted, you got the current one. Since event_bases weren’t threadsafe, this could get pretty error-prone.
nstead of event_base_new(), there was:
struct event_base *event_init(void);
This function worked like event_base_new(), and set the current base to the allocated base. There was no other way to change the current base.
Some of the event_base functions in this section had variants that operated on the current base. These functions behaved as the current functions, except that they took no base argument.
Current function |
Obsolete current-base version |
event_base_priority_init() |
event_priority_init() |
event_base_get_method() |
event_get_method() |
------------------------------------------------<the end.>----------------------------------------------------------------------------
Working with an event loop
Running the loop
Once you have an event_base with some events registered (see the next section about how to create and register events), you will want Libevent to wait for events and alert you about them.
#define EVLOOP_ONCE 0x01
#define EVLOOP_NONBLOCK 0x02
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
int event_base_loop(struct event_base *base, int flags);
Default: the event_base_loop() function runs an event_base until there are no more events registered in it. Once the registered events triggered, it marks them as "active", and starts to run them.
The behavior of event_base_loop() can be changed by setting one or more flags in its flags argument.
EVLOOP_ONCE is set, then the loop will wait until some events become active, then run active events until there are no more to run, then return.
EVLOOP_NONBLOCK is set, then the loop will not wait for events to trigger: it will only check whether any events are ready to trigger immediately, and run their callbacks if so.
EVLOOP_NO_EXIT_ON_EMPTY is set, the loop will not exit when no pending or active events, the loop will keep running until somebody calls event_base_loopbreak(), or calls event_base_loopexit(), or an error occurs.
Pseudocode:
while (any events are registered with the loop,
or EVLOOP_NO_EXIT_ON_EMPTY was set) { if (EVLOOP_NONBLOCK was set, or any events are already active)
If any registered events have triggered, mark them active.
else
Wait until at least one event has triggered, and mark it active. for (p = ; p < n_priorities; ++p) {
if (any event with priority of p is active) {
Run all active events with priority of p.
break; /* Do not run any events of a less important priority */
}
} if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
break;
}
As a convenience, you can also call:
int event_base_dispatch(struct event_base *base);
The event_base_dispatch() call is the same as event_base_loop(), with no flags set. Thus, it keeps running until there are no more registered events or until event_base_loopbreak() or event_base_loopexit() is called.
Stopping the loop
Interface
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
int event_base_loopbreak(struct event_base *base);
The event_base_loopexit() function tells an event_base to stop looping after a given time has elapsed. If the tv argument is NULL, the event_base stops looping without a delay. If the event_base is currently running callbacks for any active events, it will continue running them, and not exit until they have all been run.
The event_base_loopbreak() function tells the event_base to exit its loop immediately. It differs from event_base_loopexit(base, NULL) in that if the event_base is currently running callbacks for any active events, it will exit immediately after finishing the one it’s currently processing.
Note also that event_base_loopexit(base,NULL) and event_base_loopbreak(base) act differently when no event loop is running: loopexit schedules the next instance of the event loop to stop right after the next round of callbacks are run (as if it had been invoked with EVLOOP_ONCE) whereas loopbreak only stops a currently running loop, and has no effect if the event loop isn’t running.
Example: Shut down immediately
#include <event2/event.h> /* Here's a callback function that calls loopbreak */
void cb(int sock, short what, void *arg)
{
struct event_base *base = arg;
event_base_loopbreak(base);
} void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)
{
struct event *watchdog_event; /* Construct a new event to trigger whenever there are any bytes to
read from a watchdog socket. When that happens, we'll call the
cb function, which will make the loop exit immediately without
running any other active events at all.
*/
watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base); event_add(watchdog_event, NULL); event_base_dispatch(base);
}
Example: Run an event loop for 10 seconds, then exit.
#include <event2/event.h> void run_base_with_ticks(struct event_base *base)
{
struct timeval ten_sec; ten_sec.tv_sec = ;
ten_sec.tv_usec = ; /* Now we run the event_base for a series of 10-second intervals, printing
"Tick" after each. For a much better way to implement a 10-second
timer, see the section below about persistent timer events. */
while () {
/* This schedules an exit ten seconds from now. */
event_base_loopexit(base, &ten_sec); event_base_dispatch(base);
puts("Tick");
}
}
Sometimes you may want to tell whether your call to event_base_dispatch() or event_base_loop() exited normally, or because of a call to event_base_loopexit() or event_base_break(). You can use these functions to tell whether loopexit or break was called:
Interface
int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);
Re-checking for events
Ordinarily, Libevent checks for events, then runs all the active events with the highest priority, then checks for events again, and so on. But sometimes you might want to stop Libevent right after the current callback has been run, and tell it to scan again. By analogy to event_base_loopbreak(), you can do this with the function event_base_loopcontinue().
Interface
int event_base_loopcontinue(struct event_base *);
Calling event_base_loopcontinue() has no effect if we aren’t currently running event callbacks.
Checking the internal time cache
Sometimes you want to get an approximate view of the current time inside an event callback, and you want to get it without calling gettimeofday() yourself as a syscall.
Interface
int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv_out);
The event_base_gettimeofday_cached() function sets the value of its tv_out argument to the cached time if the event_base is currently executing callbacks. Otherwise, it calls evutil_gettimeofday() for the actual current time. It returns 0 on success, and negative on failure.
Note that since the timeval is cached when Libevent starts running callbacks, it will be at least a little inaccurate. If your callbacks take a long time to run, it may be very inaccurate. To force an immediate cache update, you can call this function:
Interface
int event_base_update_cache_time(struct event_base *base);
Dumping the event_base status
Interface
void event_base_dump_events(struct event_base *base, FILE *f);
For help debugging your program (or debugging Libevent!) you might sometimes want a complete list of all events added in the event_base and their status. Calling event_base_dump_events() writes this list to the stdio file provided.
Running a function over every event in an event_base
typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *); int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg);
You can use event_base_foreach_event() to iterate over every currently active or pending event associated with an event_base(). The provided callback will be invoked exactly once per event, in an unspecified order. The third argument of event_base_foreach_event() will be passed as the third argument to each invocation of the callback.
The callback function must return 0 to continue iteration, or some other integer to stop iterating. Whatever value the callback function finally returns will then be returned by event_base_foreach_function().
Your callback function must not modify any of the events that it receives, or add or remove any events to the event base, or otherwise modify any event associated with the event base, or undefined behavior can occur, up to or including crashes and heap-smashing.
The event_base lock will be held for the duration of the call to event_base_foreach_event() — this will block other threads from doing anything useful with the event_base, so make sure that your callback doesn’t take a long time.
Obsolete event loop functions
Current function |
Obsolete current-base version |
event_base_dispatch() |
event_dispatch() |
event_base_loop() |
event_loop() |
event_base_loopexit() |
event_loopexit() |
event_base_loopbreak() |
event_loopbreak() |
libevent reference Mannual II--library的更多相关文章
- libevent reference Mannual III--working with events
FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html Working with events Libevent’s basic unit ...
- libevent reference Mannual V -- Bufferevents
FYI: http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html Bufferevents: concepts and ba ...
- libevent reference Mannual IV --Helper functions and types
FYI: http://www.wangafu.net/~nickm/libevent-book/Ref5_evutil.html Helper functions and types for Lib ...
- libevent reference Mannual I
FYI:http://www.wangafu.net/~nickm/libevent-book/ This lib is a integral of asynchronous IO. we shoul ...
- libevent入门教程
首先给出官方文档吧: http://libevent.org ,首页有个Programming with Libevent,里面是一节一节的介绍libevent,但是感觉信息量太大了,而且还是英文的- ...
- 轻量级网络库libevent概况
Libevent is a library for writing fast portable nonblocking IO. libevent是一个为编写快速可移植的非阻塞IO程序而设计的. lib ...
- windows下编译及使用libevent
Libevent官网:http://libevent.org/ windows 7下编译: 编译环境: windows 7 + VS2010 (1)解压libevent到F:\libevent\lib ...
- [转]windows下编译及使用libevent
http://www.cnblogs.com/luxiaoxun/p/3603399.html Libevent官网:http://libevent.org/ windows 7下编译: 编译环境: ...
- android使用library工程问题
在windows系统下,library project必须和project处于相同的盘符中,因为如果在不同盘符,project.properties中的android.library.referenc ...
随机推荐
- Delphi中WebBrowser控件打开部分网站报"Invalid floating point operation”解决
Delphi中WebBrowser控件打开部分网站报"Invalid floating point operation”解决 EmbeddedWBWebBrowserDelphi 最近用E ...
- 【ZJOI2009】【Codevs 2347】假期的宿舍
http://codevs.cn/problem/2347/ Solution 二分图板子 连边:i认识j并且j是在校有床 i→j+n i有床i→i+n 还有就是找要在学校的人,1.有床不回2.没床的 ...
- 【Codevs 4672】辛苦的老园丁
http://codevs.cn/problem/4672/ 那个一看这不是(最大独立集)的最大权值和,类似 反图→ 最大团 NP问题 搜索解决 改一下模板即可 参考最大独立集 Maximum C ...
- tflearn 保存模型重新训练
from:https://stackoverflow.com/questions/41616292/how-to-load-and-retrain-tflean-model This is to cr ...
- 别再问什么是Java内存模型了,看这里!
网上有很多关于Java内存模型的文章,在<深入理解Java虚拟机>和<Java并发编程的艺术>等书中也都有关于这个知识点的介绍.但是,很多人读完之后还是搞不清楚,甚至有的人说自 ...
- bzoj2989
坐标轴转化+cdq分治 我们发现那个绝对值不太好搞,于是我们把曼哈顿距离转为切比雪夫距离,x'=x-y,y'=x+y,这样两点之间距离就是max(|x1'-x2'|,|y1'-y2'|),这个距离要小 ...
- bzoj 1233: [Usaco2009Open]干草堆tower【dp+单调栈】
参考:https://www.cnblogs.com/N-C-Derek/archive/2012/07/11/usaco_09_open_tower.html 虽然长得很像斜率优化,但是应该不算-- ...
- 383 Ransom Note 赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成.如果可以构成,返回 true :否则返回 ...
- [译]Customizing Operations
Customizing Operations定制操作 There is an ongoing development today where more and more protocols are b ...
- 【URL重写】IIS7配置URL重写
URL Rewrite Module 此模块适用于IIS7.7.5.8. 微软在IIS7中添加了URL的重写模块,并且免费使用,可以导入.htaccess规则,但需要安装. 第一步:安装URL2. ...