wangzhengquan
2021-01-19 7ec14eb603babeca5fc582138f4539af7a445702
docxygen
3个文件已添加
2 文件已重命名
6个文件已修改
443 ■■■■■ 已修改文件
CMakeLists.txt 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
build.sh 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/CMakeLists.txt 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/Doxyfile.in 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/linked-lock-free-code.png 补丁 | 查看 | 原始文档 | blame | 历史
doc/基于共享内存的生产者消费者模式的无锁队列的设计方案.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/CMakeLists.txt 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/CMakeLists.txt 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/futex_demo.cpp 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/futex_test.cpp 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test_net_socket/CMakeLists.txt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.5)
# set the project name and version
project(B_BUS VERSION 3.0)
project(B_BUS VERSION 2.2)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
@@ -17,8 +17,13 @@
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/include/usgcommon")
list(APPEND EXTRA_LIBS ${PROJECT_SOURCE_DIR}/lib/libusgcommon.a pthread)
list(APPEND EXTRA_LIBS ${PROJECT_SOURCE_DIR}/lib/libusgcommon.a pthread rt)
add_subdirectory(${PROJECT_SOURCE_DIR}/src)
add_subdirectory(${PROJECT_SOURCE_DIR}/test)
add_subdirectory(${PROJECT_SOURCE_DIR}/test_net_socket)
add_subdirectory(${PROJECT_SOURCE_DIR}/test_net_socket)
# build api doc
if (CMAKE_BUILD_TYPE MATCHES "^[Rr]elease")
    # build the docs
    add_subdirectory(${PROJECT_SOURCE_DIR}/doc)
endif()
build.sh
@@ -37,9 +37,9 @@
# -DBUILD_SHARED_LIBS=ON
# -DCMAKE_INSTALL_PREFIX=$(pwd/../dest)
# -DQCA_MAN_INSTALL_DIR:PATH=/usr/share/man 
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/../dest" -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DSUPPORT_RDMA=OFF ..
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/../dest" -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=ON -DSUPPORT_RDMA=OFF ..
cmake --build .
#cmake --build . --target install
cmake --build . --target install
 
doc/CMakeLists.txt
New file
@@ -0,0 +1,28 @@
# first we can indicate the documentation build as an option and set it to ON by default
option(BUILD_DOC "Build documentation" ON)
# check if Doxygen is installed
find_package(Doxygen)
if (DOXYGEN_FOUND)
    # set input and output files
    set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
    set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
    # request to configure the file
    configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
    message("Doxygen build started")
    # note the option ALL which allows to build the docs together with the application
    add_custom_target( doc_doxygen ALL
        COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        COMMENT "Generating API documentation with Doxygen"
        VERBATIM )
    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/api"
        DESTINATION doc
    )
else (DOXYGEN_FOUND)
  message("Doxygen need to be installed to generate the doxygen documentation. To install type common `sudo apt install -y doxygen texlive-latex-base graphviz` ")
endif (DOXYGEN_FOUND)
doc/Doxyfile.in
File was renamed from Doxyfile
@@ -58,7 +58,7 @@
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY       = build/doc
OUTPUT_DIRECTORY       = @CMAKE_CURRENT_BINARY_DIR@/api
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@@ -771,7 +771,7 @@
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT                  = src
INPUT                  = @CMAKE_SOURCE_DIR@/src @CMAKE_CURRENT_SOURCE_DIR@
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
doc/linked-lock-free-code.png

doc/»ùÓÚ¹²ÏíÄÚ´æµÄÉú²úÕßÏû·ÑÕßģʽµÄÎÞËø¶ÓÁеÄÉè¼Æ·½°¸.md
@@ -15,7 +15,7 @@
## 2 æ— é”é˜Ÿåˆ—(Free Lock)的实现
无锁队列是用细粒度的原子锁实现的,多进程操作时无阻塞并发性能高。网上有五花八门的相关算法实现。我对比了一下,决定采用下面的这个。这个算法性能好是一方面,它同时也解决了队列为空时并发操作可能出现的问题,以及ABA的问题。
![](./code.png)
![](./linked-lock-free-code.png)
## 3 ç”Ÿäº§è€…消费者之间的协作
src/CMakeLists.txt
@@ -45,34 +45,35 @@
# install rules
install(TARGETS shm_queue DESTINATION lib)
install(FILES 
    socket/socket_def.h
    socket/net_conn_pool.h
    socket/bus_server_socket.h
    socket/shm_socket.h
    socket/net_mod_socket.h
    socket/shm_stream_mod_socket.h
    socket/net_mod_server_socket_wrapper.h
    socket/net_mod_socket_io.h
    socket/net_mod_server_socket.h
    socket/shm_mod_socket.h
    socket/net_mod_socket_wrapper.h
    socket/bus_server_socket_wrapper.h
    key_def.h
    bus_error.h
    logger_factory.h
    queue/linked_lock_free_queue.h
    queue/array_lock_free_queue2.h
    queue/array_lock_free_queue.h
    queue/shm_queue.h
    queue/shm_queue_wrapper.h
    queue/lock_free_queue.h
    shm/hashtable.h
    shm/mem_pool.h
    shm/mm.h
    shm/shm_allocator.h
    shm/shm_mm_wraper.h
  socket/socket_def.h
  socket/net_conn_pool.h
  socket/bus_server_socket.h
  socket/shm_socket.h
  socket/net_mod_socket.h
  socket/shm_stream_mod_socket.h
  socket/net_mod_server_socket_wrapper.h
  socket/net_mod_socket_io.h
  socket/net_mod_server_socket.h
  socket/shm_mod_socket.h
  socket/net_mod_socket_wrapper.h
  socket/bus_server_socket_wrapper.h
  key_def.h
  bus_error.h
  px_sem_util.h
  logger_factory.h
  queue/linked_lock_free_queue.h
  queue/array_lock_free_queue2.h
  queue/array_lock_free_queue.h
  queue/shm_queue.h
  queue/lock_free_queue.h
  shm/hashtable.h
  shm/mem_pool.h
  shm/mm.h
  shm/shm_mm_wrapper.h
  shm/shm_allocator.h
  DESTINATION include)
install(FILES "${PROJECT_BINARY_DIR}/src/BusConfig.h"
install(FILES "${PROJECT_BINARY_DIR}/src/bus_config.h"
    DESTINATION include
)
test/CMakeLists.txt
@@ -1,11 +1,27 @@
# add the executable
add_executable(test1 test1.cpp )
target_link_libraries(test1 PUBLIC  ${EXTRA_LIBS} )
target_include_directories(test1 PUBLIC
target_link_libraries(test1 PRIVATE  ${EXTRA_LIBS} )
target_include_directories(test1 PRIVATE
                            "${PROJECT_BINARY_DIR}"
                             ${EXTRA_INCLUDES}
                            )
add_executable(futex_demo futex_demo.cpp )
target_link_libraries(futex_demo PRIVATE  ${EXTRA_LIBS} )
target_include_directories(futex_demo PRIVATE
                            "${PROJECT_BINARY_DIR}"
                             ${EXTRA_INCLUDES}
                            )
add_executable(futex_test futex_test.cpp )
target_link_libraries(futex_test PRIVATE  ${EXTRA_LIBS} )
target_include_directories(futex_test PRIVATE
                            "${PROJECT_BINARY_DIR}"
                             ${EXTRA_INCLUDES}
                            )
# add the install targets
install(TARGETS test1 DESTINATION bin)
test/futex_demo.cpp
New file
@@ -0,0 +1,161 @@
/* futex_demo.c
Usage: futex_demo [nloops]
(Default: 5)
Demonstrate the use of futexes in a program where parent and child
use a pair of futexes located inside a shared anonymous mapping to
synchronize access to a shared resource: the terminal. The two
processes each write 'num-loops' messages to the terminal and employ
a synchronization protocol that ensures that they alternate in
writing messages.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/time.h>
#include "usg_common.h"
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static int *futex1, *futex2, *iaddr;
  static int
futex(int *uaddr, int futex_op, int val,
    const struct timespec *timeout, int *uaddr2, int val3)
{
  return syscall(SYS_futex, uaddr, futex_op, val,
      timeout, uaddr, val3);
}
/* Acquire the futex pointed to by 'futexp': wait for its value to
   become 1, and then set the value to 0. */
  static void
fwait(int *futexp)
{
  int s;
  /* __sync_bool_compare_and_swap(ptr, oldval, newval) is a gcc
     built-in function.  It atomically performs the equivalent of:
     if (*ptr == oldval)
   *ptr = newval;
   It returns true if the test yielded true and *ptr was updated.
   The alternative here would be to employ the equivalent atomic
   machine-language instructions.  For further information, see
   the GCC Manual. */
  while (1) {
    /* Is the futex available? */
    if (__sync_bool_compare_and_swap(futexp, 1, 0))
      break;      /* Yes */
    /* Futex is not available; wait */
    s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0);
    if (s == -1 && errno != EAGAIN)
      errExit("futex-FUTEX_WAIT");
  }
}
/* Release the futex pointed to by 'futexp': if the futex currently
   has the value 0, set its value to 1 and the wake any futex waiters,
   so that if the peer is blocked in fpost(), it can proceed. */
  static void
fpost(int *futexp)
{
  int s;
  /* __sync_bool_compare_and_swap() was described in comments above */
  if (__sync_bool_compare_and_swap(futexp, 0, 1)) {
    s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0);
    if (s  == -1)
      errExit("futex-FUTEX_WAKE");
  }
}
  int
main(int argc, char *argv[])
{
  pid_t childPid;
  int j, nloops;
  int flags, opt, fd;
  mode_t perms;
  size_t size;
  setbuf(stdout, NULL);
  nloops = (argc > 1) ? atoi(argv[1]) : 5;
  flags = O_RDWR | O_CREAT | O_EXCL;
  perms = S_IRUSR | S_IWUSR;
  size = sizeof(int) * 2;
  fd = shm_open("futex_demo", flags, perms);
  if (fd == -1)
  errExit("shm_open");
  if (ftruncate(fd, size) == -1)
  errExit("ftruncate");
  /* Create a shared anonymous mapping that will hold the futexes.
     Since the futexes are being shared between processes, we
     subsequently use the "shared" futex operations (i.e., not the
     ones suffixed "_PRIVATE") */
  iaddr = (int *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, fd, 0);
  if (iaddr == MAP_FAILED)
    errExit("mmap");
  futex1 = &iaddr[0];
  futex2 = &iaddr[1];
  *futex1 = 0;        /* State: unavailable */
  *futex2 = 1;        /* State: available */
  /* Create a child process that inherits the shared anonymous
     mapping */
  childPid = fork();
  if (childPid == -1)
    errExit("fork");
  if (childPid == 0) {        /* Child */
    for (j = 0; j < nloops; j++) {
      fwait(futex1);
      printf("Child  (%ld) %d\n", (long) getpid(), j);
      fpost(futex2);
    }
    exit(EXIT_SUCCESS);
  }
  /* Parent falls through to here */
  for (j = 0; j < nloops; j++) {
    fwait(futex2);
    printf("Parent (%ld) %d\n", (long) getpid(), j);
    fpost(futex1);
  }
  wait(NULL);
  exit(EXIT_SUCCESS);
}
test/futex_test.cpp
New file
@@ -0,0 +1,148 @@
/* futex_demo.c
Usage: futex_demo [nloops]
(Default: 5)
Demonstrate the use of futexes in a program where parent and child
use a pair of futexes located inside a shared anonymous mapping to
synchronize access to a shared resource: the terminal. The two
processes each write 'num-loops' messages to the terminal and employ
a synchronization protocol that ensures that they alternate in
writing messages.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/time.h>
#include "usg_common.h"
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static int *futex1, *futex2, *iaddr;
  static int
futex(int *uaddr, int futex_op, int val,
    const struct timespec *timeout, int *uaddr2, int val3)
{
  return syscall(SYS_futex, uaddr, futex_op, val,
      timeout, uaddr, val3);
}
/* Acquire the futex pointed to by 'futexp': wait for its value to
   become 1, and then set the value to 0. */
  static void
fwait(int *futexp)
{
  int s;
  /* __sync_bool_compare_and_swap(ptr, oldval, newval) is a gcc
     built-in function.  It atomically performs the equivalent of:
     if (*ptr == oldval)
   *ptr = newval;
   It returns true if the test yielded true and *ptr was updated.
   The alternative here would be to employ the equivalent atomic
   machine-language instructions.  For further information, see
   the GCC Manual. */
  while (1) {
    /* Is the futex available? */
    if (__sync_bool_compare_and_swap(futexp, 1, 0))
      break;      /* Yes */
    /* Futex is not available; wait */
    s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0);
    if (s == -1 && errno != EAGAIN)
      errExit("futex-FUTEX_WAIT");
  }
}
/* Release the futex pointed to by 'futexp': if the futex currently
   has the value 0, set its value to 1 and the wake any futex waiters,
   so that if the peer is blocked in fpost(), it can proceed. */
  static void
fpost(int *futexp)
{
  int s;
  /* __sync_bool_compare_and_swap() was described in comments above */
  if (__sync_bool_compare_and_swap(futexp, 0, 1)) {
    s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0);
    if (s  == -1)
      errExit("futex-FUTEX_WAKE");
  }
}
  int
main(int argc, char *argv[])
{
  pid_t childPid;
  int j, nloops;
  int   opt, fd;
  mode_t perms;
  size_t size;
  bool first = true;
  setbuf(stdout, NULL);
  nloops = (argc > 1) ? atoi(argv[1]) : 5;
  perms = S_IRUSR | S_IWUSR;
  size = sizeof(int) ;
  fd = shm_open("futex_test",  O_RDWR | O_CREAT  | O_EXCL, perms);
  if (fd == -1 && errno == EEXIST) {
    fd = shm_open("futex_test", O_RDWR, perms);
    first = false;
  }
  if(fd == -1) {
      errExit("shm_open");
  }
  if (ftruncate(fd, size) == -1)
  errExit("ftruncate");
  /* Create a shared anonymous mapping that will hold the futexes.
     Since the futexes are being shared between processes, we
     subsequently use the "shared" futex operations (i.e., not the
     ones suffixed "_PRIVATE") */
  iaddr = (int *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (iaddr == MAP_FAILED)
    errExit("mmap");
  futex1 = iaddr;
  if(first) {
    *futex1 = 1;
  }
  /* State: available */
  fwait(futex1);
  printf("(%ld) è¿›å…¥äº’斥区\n", (long) getpid());
  sleep(5);
  fpost(futex1);
  exit(EXIT_SUCCESS);
}
test_net_socket/CMakeLists.txt
@@ -13,14 +13,14 @@
# add the executable
add_executable(test_net_mod_socket test_net_mod_socket.cpp  ${CMAKE_CURRENT_BINARY_DIR}/net_mod_socket.sh)
target_link_libraries(test_net_mod_socket PUBLIC shm_queue  ${EXTRA_LIBS} )
target_link_libraries(test_net_mod_socket PRIVATE shm_queue  ${EXTRA_LIBS} )
add_executable(heart_beat heart_beat.cpp ${CMAKE_CURRENT_BINARY_DIR}/heart_beat.sh)
target_link_libraries(heart_beat PUBLIC shm_queue )
# target_link_libraries(heart_beat PUBLIC shm_queue  ${EXTRA_LIBS} )
target_link_libraries(heart_beat PRIVATE shm_queue )
# target_link_libraries(heart_beat PRIVATE shm_queue  ${EXTRA_LIBS} )
target_include_directories(test_net_mod_socket PUBLIC
target_include_directories(test_net_mod_socket PRIVATE
                            "${PROJECT_BINARY_DIR}"
                             ${EXTRA_INCLUDES}
                            )