Posts Tagged ‘cbthreads’

Dinesh Premalal in his blog post on Axis2/C with cbthread explain that using cbthreads he ran about 100,000 concurrent requests using Axis2/C client. The reason for this achievement is because of the non-preemptive and continuation-based threads implemented with cbthreads. However in his next blog Axis2/C with pthreads he goes on explaining how he used similer Axis2/C client with pthreads and could only run about 300 concurrent requests. This is predictable because each thread in pthreads consume considerable amount of memory in it’s stack-based nature implementation. In adition Dinesh’s program for pthreads does not use a thread pool which cause the the program to create threads until system resources exhausted.

In cbthreads home page it is mentioned

“A downside of having a non-preemptive thread system is that you cannot assign threads to blocking system calls as you can with pthreads, and have threads run while the system call blocks. If you do, the entire process blocks.”

This reason highly discourage using cbthreads for Axis2/C. Besides pthreads is provenly portable among numerous platforms. In my opinion what Axis2/C needs is a good thread pool implementation using pthreads.

In search of a good thread pool using pthreads I came across this one which seems to be a good candidate. I wrote a similer client as Dinesh wrote for testing cbthreads using this pthreads thread pool.

Axis2/C client With pthread threadpool for 10,000 request
real 1m9.974s
user 0m34.890s
sys 0m9.297s

Axis2/C client with cbthreads for 10,000 requests
real 3m29.835s
user 0m13.621s
sys 0m8.857s

This shows that using pthreads with a good thread pool is the right way to use pthreads for Axis2/C with it’s all proven features.

To try this with Axis2/C echo.cpp client program do the following steps.

1. Download the pthread pool from here and build the source by executing make in the root source folder.

2. Install Axis2/C. I assume you installed it into /axis2c/deploy.(You need Axis2/C 1.6 or build it from svn source)

3. Copy the following echo.cpp source file and build.sh build script into the same source folder.

4. Execute build.sh and run the exectuable program.

One thing to notice about the echo.cpp code is creating service client for each thread. Main overhead of creating service client is associated with creating the Axis2/C main cofiguration context. This is reduced by creating each service client passing the same configuratin context as following.

conf_ctx = axis2_svc_client_get_conf_ctx(svc_client, env);
svc = axis2_svc_client_get_svc(svc_client, env);
svc_client = axis2_svc_client_create_with_conf_ctx_and_svc(env, client_home, conf_ctx, svc);


#include <TThreadPool.hh>
#include <stdio.h>
#include <stdio.h>
#include <axiom.h>
#include <axis2_util.h>
#include <axiom_soap.h>
#include <axis2_client.h>
#include <axis2_conf_ctx.h>
#include <axis2_svc.h>

#define NTHREADS 10000
#define POOLSIZE 100

axiom_node_t *
build_om_payload_for_echo_svc(const axutil_env_t * env);

typedef struct _svcinfo {
    const axutil_env_t *env;
    axis2_svc_client_t *svc_client;
    axis2_char_t *address;

static void svc_client_send_request (void *v);

class echo : public TThreadPool::TJob
   echo ( int id )
       : TThreadPool::TJob( id )

  void run ( void * arg )

main(int argc, char **argv)
    const axutil_env_t *env = NULL;
    const axis2_char_t *address = NULL;
    axis2_endpoint_ref_t *endpoint_ref = NULL;
    axis2_options_t *options = NULL;
    const axis2_char_t *client_home = NULL;
    axis2_svc_client_t *svc_client = NULL;
    int i = 0;
    TThreadPool * pool = NULL;
    axis2_conf_ctx_t *conf_ctx = NULL;
    axis2_svc_t *svc = NULL;

    /* Set up the environment */
    env = axutil_env_create_all("echo.log", AXIS2_LOG_LEVEL_TRACE);

    /* Set end point reference of echo service */
    address = "http://localhost:9091/axis2/services/echo";
    if (argc > 1)
        if (axutil_strcmp(argv[1], "-h") == 0)
            printf("Usage : %s [endpoint_url]\n",
            printf("use -h for help\n");
            return 0;
            address = argv[1];
    printf("Using endpoint : %s\n", address);

    /* Set up deploy folder. It is from the deploy folder, the configuration is picked up
     * using the axis2.xml file.
     * In this sample client_home points to the Axis2/C default deploy folder. The client_home can
     * be different from this folder on your system. For example, you may have a different folder
     * (say, my_client_folder) with its own axis2.xml file. my_client_folder/modules will have the
     * modules that the client uses
    client_home = AXIS2_GETENV("AXIS2C_HOME");
    if (!client_home || !strcmp(client_home, ""))
        client_home = "../..";

    /* Create service client */
    svc_client = axis2_svc_client_create(env, client_home);
    if (!svc_client)
            ("Error creating service client, Please check AXIS2C_HOME again\n");
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
        return -1;

    /* Set service client options */
    axis2_svc_client_set_options(svc_client, env, options);

    /* Engage addressing module */
    axis2_svc_client_engage_module(svc_client, env, AXIS2_MODULE_ADDRESSING);

    conf_ctx = axis2_svc_client_get_conf_ctx(svc_client, env);
    svc = axis2_svc_client_get_svc(svc_client, env);
    pool = new TThreadPool( POOLSIZE );

    for (i = 0; i < NTHREADS; i++)
        echo *job = new echo(i);
        axis2_svc_client_t *t_client = NULL;
        svc_info_t *svcinfo = NULL;

        svcinfo = (svc_info_t *) malloc (sizeof (svc_info_t));
        if (!svcinfo)
            fprintf (stderr, "no enough memory\n");
            exit (1);
        svcinfo->env = env;
        t_client = axis2_svc_client_create_with_conf_ctx_and_svc(env, client_home, conf_ctx, svc);
        svcinfo->svc_client = t_client;
        svcinfo->address = (axis2_char_t *) address;
        pool->run( job, (void *) svcinfo, true );

    axis2_svc_client_free(svc_client, env);
    return 0;

/* build SOAP request message content using OM */
axiom_node_t *
    const axutil_env_t * env)
    axiom_node_t *echo_om_node = NULL;
    axiom_element_t *echo_om_ele = NULL;
    axiom_node_t *text_om_node = NULL;
    axiom_element_t *text_om_ele = NULL;
    axiom_namespace_t *ns1 = NULL;
    axis2_char_t *om_str = NULL;

    ns1 =
        axiom_namespace_create(env, "http://ws.apache.org/axis2/services/echo",
    echo_om_ele =
        axiom_element_create(env, NULL, "echoString", ns1, &echo_om_node);
    text_om_ele =
        axiom_element_create(env, echo_om_node, "text", NULL, &text_om_node);
    axiom_element_set_text(text_om_ele, env, "Hello World!", text_om_node);
    om_str = axiom_node_to_string(echo_om_node, env);

    if (om_str)
        AXIS2_FREE(env->allocator, om_str);
        om_str = NULL;
    return echo_om_node;

static void
svc_client_send_request (void *v)
    svc_info_t *svcinfo;
    const axutil_env_t *env;
    axis2_svc_client_t *svc_client;
    axiom_node_t *payload = NULL;
    axiom_node_t *ret_node;
    axis2_options_t *options = NULL;
    axis2_endpoint_ref_t *endpoint_ref = NULL;
    axis2_char_t *address = NULL;

    svcinfo = (svc_info_t *)v;
    env = svcinfo->env;
    svc_client = svcinfo->svc_client;
    address = svcinfo->address;

    options = (axis2_options_t *) axis2_svc_client_get_options(svc_client, env);
        options = axis2_options_create(env);
        axis2_svc_client_set_options(svc_client, env, options);

    endpoint_ref = axis2_endpoint_ref_create(env, address);

    axis2_options_set_to(options, env, endpoint_ref);
    axis2_options_set_action(options, env,

    /* Build the SOAP request message payload using OM API. */
    payload = build_om_payload_for_echo_svc(env);

    /* Send request */
    ret_node = axis2_svc_client_send_receive(svc_client, env, payload);

    if (ret_node)
        axiom_node_free_tree(payload, env);
        axiom_node_free_tree(ret_node, env);
        ret_node = NULL;
        printf("Invoke SUCCESSFUL\n");
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                        "Stub invoke FAILED: Error code:" " %d :: %s",
        printf("echo client invoke FAILED\n");

        AXIS2_FREE(env->allocator, svcinfo);
        svcinfo = NULL;
    axis2_svc_client_free(svc_client, env);


gcc *.cpp -oecho -I./src libthrpool.a -lstdc++ -lpthread -L/axis2c/deploy/lib -lm -laxis2_engine -laxutil -laxis2_axiom -I. -I/axis2c/deploy/include/axis2-1.6.0/

Read Full Post »