Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

child thread, zsocket_set_linger assert error,when main thread call zctx_destroy (&ctx); #199

Closed
balanceren opened this issue Jun 26, 2013 · 10 comments

Comments

@balanceren
Copy link

in Windows platform.
when main thread call zctx_destroy (&ctx), the child thread created by zthread_fork, cause assert false in zsocket_set_linger();

I am not clear the zthread lib, so I add
void * child = zthread_fork(ctx, client_task, "child1");
......
zstr_send(child,"DELETE"); //the client_task handle the DELETE cmd
char * str = zstr_recv(child);
free(str);
zctx_destroy (&ctx);

use zstr_recv to wait the client_task finish.
work like join.

is there a fun works like zthread_join.

@ulikoehler
Copy link
Contributor

Could you provide more information about the assertion that fails?
Maybe this is related to #164

@balanceren
Copy link
Author

sorry,i don't know how to modify the style to make the code clear.

int main (void)
{
    zctx_t *ctx = zctx_new ();
    void * child = zthread_fork(ctx, client_task, "child1");
    int t = 0;
    while(!zctx_interrupted && t != 20)
    {
        char cmd[10]={0};
        sprintf(cmd,"Get %d\n",t++);
        zstr_send(child,cmd);
        Sleep(300);
    }
    /*
    if I don't do these below, 
    the assert false,after call zctx_destroy (&ctx);
    */
    //zstr_send(child,"DELETE");
    //char * str = zstr_recv(child);
    //free(str);

    zctx_destroy (&ctx);
    return 0;
}

static void client_task (void *args, zctx_t *ctx, void *pipe)
{
    void * client = zsocket_new (ctx, ZMQ_DEALER);
    void * sub   = zsocket_new(ctx,ZMQ_SUB);
    char identity [10]={0};
    if(args)
    {
        int len = min(strlen((char *)args),9);
        memcpy(identity,args,len);
        zsockopt_set_identity (client, identity);
    }

    zsocket_connect (client, "tcp://localhost:5570");
    zsocket_connect (sub, "tcp://localhost:5556");
    bool run = true;
    while (run) {
        zmq_pollitem_t items [] = { 
            { client, 0, ZMQ_POLLIN, 0 },
            { sub, 0, ZMQ_POLLIN, 0 },
            { pipe, 0, ZMQ_POLLIN, 0 }};

            int rc = zmq_poll (items, 3, 1000);
            if (rc == -1)
                break;          //  Interrupted
            if (items [0].revents & ZMQ_POLLIN)
            {
                printf("client\n");
            }
            if (items [1].revents & ZMQ_POLLIN)
            {
                printf("sub\n");
            }
            if (items [2].revents & ZMQ_POLLIN)
            {
                char * str = zstr_recv (pipe);
                printf("pipe__%s\n",str);
                if(strcmp(str,"DELETE")==0)
                    run = false;
                else    //cmd
                    zstr_send(client,str);
                free(str);
            }
    }
    zstr_send(pipe,"END");
    zsocket_destroy(ctx,client);
    zsocket_destroy(ctx,sub);
}

@hintjens
Copy link
Member

I've not tried yet to reproduce this, but try removing the
zsocket_destroy() calls. You don't need these and they may be causing
zctx_destroy confusion. It shouldn't assert anyhow.

On Wed, Jun 26, 2013 at 4:02 PM, balanceren notifications@github.comwrote:

int main (void)
{
zctx_t ctx = zctx_new ();
*
void * child = zthread_fork(ctx, client_task, "child1");
*

  • int t = 0;
    while(!zctx_interrupted && t != 20)
    {
    char cmd[10]={0};
    sprintf(cmd,"Get %d\n",t++);
    zstr_send(child,cmd);
    Sleep(300);
    }
    /*
    if I don't do these below,
    the assert false,after call zctx_destroy (&ctx);
    */
    //zstr_send(child,"DELETE");
    //char * str = zstr_recv(child);
    //free(str);

zctx_destroy (&ctx);
return 0;

}

static void client_task (void *args, zctx_t *ctx, void *pipe)
{
void * client = zsocket_new (ctx, ZMQ_DEALER);
void * sub = zsocket_new(ctx,ZMQ_SUB);
char identity [10]={0};
if(args)
{
int len = min(strlen((char *)args),9);
memcpy(identity,args,len);
zsockopt_set_identity (client, identity);
}

zsocket_connect (client, "tcp://localhost:5570");

zsocket_connect (sub, "tcp://localhost:5556");
bool run = true;
while (run) {
zmq_pollitem_t items [] = {
{ client, 0, ZMQ_POLLIN, 0 },
{ sub, 0, ZMQ_POLLIN, 0 },
{ pipe, 0, ZMQ_POLLIN, 0 }};

int rc = zmq_poll (items, 3, 1000);
if (rc == -1)
    break;          //  Interrupted
if (items [0].revents & ZMQ_POLLIN)
{
    printf("client\n");
}
if (items [1].revents & ZMQ_POLLIN)
{
    printf("sub\n");
}
if (items [2].revents & ZMQ_POLLIN)
{
    char * str = zstr_recv (pipe);
    printf("pipe__%s\n",str);
    if(strcmp(str,"DELETE")==0)
        run = false;
    else    //cmd
        zstr_send(client,str);
    free(str);
}

}
zstr_send(pipe,"END");
zsocket_destroy(ctx,client);
zsocket_destroy(ctx,sub);

}


Reply to this email directly or view it on GitHubhttps://github.com//issues/199#issuecomment-20049236
.

@balanceren
Copy link
Author

In first version,I didn't add the zsocket_destroy() ,it is the same error

@balanceren
Copy link
Author

I debug the zmq when it term, and find the bug, but I don't know how to fix it.

when the child thread get the term cmd,and
call zctx__socket_destroy,this below code will call

void zsocket_set_linger (void *zocket, int linger) 
{
#   if defined (ZMQ_LINGER)
    int rc = zmq_setsockopt (zocket, ZMQ_LINGER, &linger, sizeof (int));
    printf("errorno =%x=%d____%d\n",_errno(),errno,ETERM);
    assert (rc == 0 || errno == ETERM);

the assert condition is rc and the errno,
if the ctx_terminated is true, the errno will be set to ETERM,

  int zmq::socket_base_t::setsockopt (int option_, const void *optval_,
     size_t optvallen_)
 {
     if (unlikely (ctx_terminated)) {
        errno = ETERM;
        printf("setsockopt =%x=%d____%d\n",_errno(),errno,ETERM);
        return -1;
    }

but, I found the _errno() has different address, so It is the reason why errno != ETERM.

@hintjens
Copy link
Member

Can you get more information?

  • which socket is this failing on
  • which zctx, the parent or the child thread
  • what is the errno that it is actually getting

Thanks

On Thu, Jun 27, 2013 at 4:22 AM, balanceren notifications@github.comwrote:

I debug the zmq when it term, and find the bug, but I don't know how to
fix it.

when the child thread get the term cmd,and
call zctx__socket_destroy,this below code will call
void zsocket_set_linger (void *zocket, int linger)
{

if defined (ZMQ_LINGER)

int rc = zmq_setsockopt (zocket, ZMQ_LINGER, &linger, sizeof (int));
printf("errorno =%x=%d____%d\n",_errno(),errno,ETERM);
assert (rc == 0 || errno == ETERM);

the assert condition is rc and the errno,
if the ctx_terminated is true, the errno will be set to ETERM,
int zmq::socket_base_t::setsockopt (int option_, const void *optval_,
size_t optvallen_)
{
if (unlikely (ctx_terminated)) {
errno = ETERM;

    printf("setsockopt =%x=%d____%d\n",_errno(),errno,ETERM);

    return -1;
}

but, I found the _errno() has different address, so It is the reason why
errno != ETERM.


Reply to this email directly or view it on GitHubhttps://github.com//issues/199#issuecomment-20093330
.

@balanceren
Copy link
Author

there is the code in my previous reply, you can test it.

if the _errno() got same address, the code is ok.

I compile the zmq to static lib and link to my app, and then the _errno() got the same address.

if I compile the zmq to dll in windows, the _errno() got different address

@hintjens
Copy link
Member

I can't test the code, don't have a Windows box, and the problem doesn't
happen on Windows.

What I know is that on Windows, errno is per-thread; this is why _errno()
has different addresses in some cases. It means if one thread sets it,
another thread won't get the same value.

Could you try to get me the information I asked for, then I'll try to see
what might be happening.

On Fri, Jun 28, 2013 at 8:47 AM, balanceren notifications@github.comwrote:

there is the code in my previous reply, you can test it.

if the _errno() got same address, the code is ok.

I compile the zmq to static lib and link to my app, and then the _errno()
got the same address.

if I compile the zmq to dll in windows, the _errno() got different address


Reply to this email directly or view it on GitHubhttps://github.com//issues/199#issuecomment-20172998
.

@balanceren
Copy link
Author

the errno is per dll,
http://social.msdn.microsoft.com/Forums/vstudio/en-US/b4500c0d-1b69-40c7-9ef5-08da1025b5bf/setting-errno-from-within-a-dll

I suggest the zcmq use a self errno to manage the errno status.

@hintjens
Copy link
Member

OK, thanks for explaining it. I've pushed a patch that should fix this: #202

ulikoehler added a commit that referenced this issue Jun 29, 2013
Problem: errno is DLL specific on Windows (#199)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants