Проект libfiber берёт начало от модуля корутины проекта acl и находится в каталоге lib_fiber. Его можно использовать на платформах ОС, включая Linux, FreeBSD, MacOS и Windows, которые поддерживают select, poll, epoll, io-uring, kqueue, iocp и даже сообщения Windows GUI для разных платформ. С помощью libfiber вы можете писать сетевые приложения с высокой производительностью и большим количеством одновременных подключений легче, чем в традиционных асинхронных фреймворках с управляемой событиями моделью. Более того, с помощью libfiber можно даже писать сетевой модуль для приложений Windows GUI, написанных на MFC, wtl или других фреймворках, в стиле корутин. Это действительно потрясающе.
Libfiber поддерживает множество событий, включая select/poll/epoll/io-uring/kqueue и сообщения Windows GUI.
Платформа | Тип события |
---|---|
Linux | select, poll, epoll, io-uring |
BSD | select, poll, kqueue |
Mac | select, poll, kqueue |
Windows | select, poll, iocp, сообщения GUI |
// fiber_server.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // in the samples path
static size_t __stack_size = 128000;
static const char *__listen_ip = "127.0.0.1";
static int __listen_port = 9001;
static void fiber_client(ACL_FIBER *fb, void *ctx)
{
SOCKET *pfd = (SOCKET *) ctx;
char buf[8192];
while (1) {
#if defined(_WIN32)
int ret = acl_fiber_recv(*pfd, buf, sizeof(buf), 0);
#else
int ret = recv(*pfd, buf, sizeof(buf), 0);
#endif
if (ret == 0) {
break;
} else if (ret < 0) {
if (acl_fiber_last_error() == FIBER_EINTR) {
continue;
}
break;
}
#if defined(_WIN32)
if (acl_fiber_send(*pfd, buf, ret, 0) < 0) {
#else
if (send(*pfd, buf, ret, 0) < 0) {
#endif
break;
}
}
socket_close(*pfd);
free(pfd);
}
static void fiber_accept(ACL_FIBER *fb, void *ctx)
{
const char *addr = (const char *) ctx;
SOCKET lfd = socket_listen(__listen_ip, __listen_port);
assert(lfd >= 0);
for (;;) {
SOCKET *pfd, cfd = socket_accept(lfd);
if (cfd == INVALID_SOCKET) {
printf("accept error %s\r\n", acl_fiber_last_serror());
break;
}
pfd = (SOCKET *) malloc(sizeof(SOCKET));
*pfd = cfd;
// create and start one fiber to handle the client socket IO
acl_fiber_create(fiber_client, pfd, __stack_size);
}
socket_close(lfd);
exit (0);
}
// FIBER_EVENT_KERNEL представляет тип события на
// Linux(epoll), BSD(kqueue), Mac(kqueue), Windows(iocp)
// FIBER_EVENT_POLL: poll на Linux/BSD/Mac/Windows
// FIBER_EVENT_SELECT: select на Linux/BSD/Mac/Windows
// FIBER_EVENT_WMSG: Win GUI message на Windows
// acl_fiber_create/acl_fiber_schedule_with находятся в `lib_fiber.h`.
// socket_listen/socket_accept/socket_close находятся в patch.c из пути примеров.
int main(void)
{
int event_mode = FIBER_EVENT_KERNEL;
#if defined(_WIN32)
socket_init();
#endif
// create
...
**Примечание:** В запросе присутствуют фрагменты кода на языке C. В ответе они сохранены без изменений. **Один из вариантов перевода текста на русский язык:**
### Один клиентский образец
```C
// fiber_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // в папке с образцами
static const char *__server_ip = "127.0.0.1";
static int __server_port = 9001;
// socket_init/socket_end/socket_connect/socket_close находятся в patch.c папки с образцами
static void fiber_client(ACL_FIBER *fb, void *ctx)
{
SOCKET cfd = socket_connect(__server_ip, __server_port);
const char *s = "hello world\r\n";
char buf[8192];
int i, ret;
if (cfd == INVALID_SOCKET) {
return;
}
for (i = 0; i < 1024; i++) {
#if defined(_WIN32)
if (acl_fiber_send(cfd, s, strlen(s), 0) <= 0) {
#else
if (send(cfd, s, strlen(s), 0) <= 0) {
#endif
printf("send error %s\r\n", acl_fiber_last_serror());
break;
}
#if defined(_WIN32)
ret = acl_fiber_recv(cfd, buf, sizeof(buf), 0);
#else
ret = recv(cfd, buf, sizeof(buf), 0);
#endif
if (ret <= 0) {
break;
}
}
#if defined(_WIN32)
acl_fiber_close(cfd);
#else
close(cfd);
#endif
}
int main(void)
{
int event_mode = FIBER_EVENT_KERNEL;
size_t stack_size = 128000;
int i;
#if defined(_WIN32)
socket_init();
#endif
for (i = 0; i < 100; i++) {
acl_fiber_create(fiber_client, NULL, stack_size);
}
acl_fiber_schedule_with(event_mode);
#if defined(_WIN32)
socket_end();
#endif
return 0;
}
#include "acl_cpp/lib_acl.hpp"
#include "fiber/libfiber.hpp"
class fiber_client : public acl::fiber {
public:
fiber_client(acl::socket_stream* conn) : conn_(conn) {}
private:
~fiber_client(void) { delete conn_; }
private:
acl::socket_stream* conn_;
// @override
void run(void) {
char buf[256];
while (true) {
int ret = conn_->read(buf, sizeof(buf), false);
if (ret <= 0) {
break;
}
if (conn_->write(buf, ret) != ret) {
break;
}
}
delete this;
}
};
class fiber_server : public acl::fiber {
public:
fiber_server(acl::server_socket& server) : server_(server) {}
private:
~fiber_server(void) {}
private:
acl::server_socket& server_;
// @override
void run(void) {
while (true) {
acl::socket_stream* conn = server_.accept();
if (conn) {
acl::fiber* fb = new fiber_client(conn);
fb->start();
}
}
delete this;
}
};
int main(void) {
const char* addr = "127.0.0.1:8088";
acl::server_socket server;
if (!server.open(addr)) {
return 1;
}
// Создаём одну серверную сопрограмму для ожидания соединения.
acl::fiber* fb = new fiber_server(server);
fb->start();
acl::fiber::schedule(); // Запускаем процесс расписания сопрограммы.
return 0;
}
#include "acl_cpp/lib_acl.hpp"
#include "fiber/go_fiber.hpp"
int main(void) {
const char* addr = "127.0.0.1:8088";
acl::server_socket server;
if (!server.open(addr)) {
return 1;
}
// Создаём одну серверную сопрограмму для ожидания соединения.
go[=, &server] {
while (true) {
acl::socket_stream* conn = server.accept();
if (conn) {
// Создаём одну клиентскую сопрограмму для обработки соединения.
go[conn] {
char buf[256];
while (true) {
int ret = conn->read(buf, sizeof(buf), false);
if (ret <= 0) {
break;
}
if (conn->write(buf, ret) != ret) {
``` **ACL_FIBER_RWLOCK**
- acl_fiber_rwlock_tryrlock
- acl_fiber_rwlock_wlock
- acl_fiber_rwlock_trywlock
- acl_fiber_rwlock_runlock
- acl_fiber_rwlock_wunlock
**ACL_FIBER_EVENT**
- acl_fiber_event_create
- acl_fiber_event_free
- acl_fiber_event_wait
- acl_fiber_event_trywait
- acl_fiber_event_notify
**ACL_FIBER_SEM**
- acl_fiber_sem_create
- acl_fiber_sem_free
- acl_fiber_sem_wait
- acl_fiber_sem_post
- acl_fiber_sem_num
## About API Hook
В Linux/BSD/Mac перехватываются многие IO и сетевые API. Поэтому вы можете просто использовать стандартные системные API в своих приложениях с libfiber, перехватченные API будут заменены на API libfiber. В этом случае вы можете *сопрограммировать* ваше приложение БД с управлением MySQL и ничего не менять в управлении MySQL.
Ниже приведены стандартные API, которые были перехвачены:
— close;
— sleep;
— read;
— readv;
— recv;
— recvfrom;
— recvmsg;
— write;
— writev;
— send;
— sendto;
— sendmsg;
— sendfile64;
— socket;
— listen;
— accept;
— connect;
— select;
— poll;
— epoll: epoll_create, epoll_ctl, epoll_wait;
— gethostbyname(_r);
— getaddrinfo/freeaddrinfo.
## FAQ
1. **Планируется ли расписание сопрограмм в многопоточном режиме?**
Нет. Расписание сопрограммы libfiber осуществляется в одном потоке. Но вы можете запустить несколько потоков, каждый из которых имеет свой процесс расписания.
2. **Как используются многоядерные процессоры?**
Можно запускать несколько потоков со своим расписанием сопрограмм, каждый поток может занимать одно ядро процессора.
3. **Каким образом разные потоки используют мьютексы в состоянии расписания сопрограмм?**
Хотя можно использовать системные мьютекс-API, такие как pthread_mutex_t, рекомендуется использовать ACL_FIBER_EVENT API. Это безопасно, когда системные мьютекс-API используются в течение короткого времени без рекурсивного вызова. Однако небезопасно использовать системные мьютекс-API в этом случае: одна сопрограмма A1 потока A заблокировала поток-мьютекс-A, сопрограмма A2 потока A хотела заблокировать поток-мьютекс-B, который был заблокирован одной сопрограммой B1 потока B, когда сопрограмма B2 потока B хотела заблокировать поток-мьютекс-A, произошла тупиковая ситуация! Таким образом, были созданы мьютексы сопрограмм для потоков и сопрограмм с именем ACL_FIBER_EVENT, которые можно использовать для создания критической области между несколькими сопрограммами в разных потоках (несколько продолжений в одном и том же потоке или нет; его также можно использовать для разных потоков без сопрограмм).
4. **Нужно ли изменять исходный код, управляемый MySQL, при использовании с libfiber?**
В UNIX OS системные IO API перехватываются libfiber, поэтому в MySQL-управляемом ничего менять не нужно.
5. **Как избежать перегрузки mysqld при запуске множества сопрограмм?**
Для защиты mysqld от перегрузки множеством соединений множества сопрограмм можно использовать API ACL_FIBER_SEM. Эти API могут ограничить количество подключений к mysqld из сопрограмм.
6. **Блокирует ли разрешение доменного имени DNS расписание сопрограмм?**
Нет, потому что системные API разрешения доменных имён, такие как gethostbyname(_r) и getaddrinfo, также перехватываются в libfiber.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )