Linux多线程之互斥

题目

共要卖票20张,由命令行输入窗口数,由线程模拟窗口。每卖掉一张票,屏幕显示由几号窗口所卖,一并显示剩余票数

思路

由于票数 ticket_cnt 是全局变量,因此每当一个线程将其减一(卖出一张票),并将其显示,应该被封装为一个原子操作。因为线程是并发执行的,可能当前线程将ticket_cnt减1后还没有来得及显示此时的剩余票数ticket_cnt,ticket_cnt已经被另一个线程减一了。此处通过互斥锁实现互斥。

函数原型

创建线程:

NAME

       pthread_create - create a new thread



SYNOPSIS

       #include <pthread.h>



       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

                          void *(*start_routine) (void *), void *arg);



       Compile and link with -pthread.

回收线程资源,该函数为阻塞函数。

NAME

       pthread_join - join with a terminated thread



SYNOPSIS

       #include <pthread.h>



       int pthread_join(pthread_t thread, void **retval);



       Compile and link with -pthread.



DESCRIPTION

       The  pthread_join() function waits for the thread specified

       by thread to terminate.  If that thread has already  termi-

       nated, then pthread_join() returns immediately.  The thread

       specified by thread must be joinable.



       If retval is not NULL, then pthread_join() copies the  exit

       status  of the target thread (i.e., the value that the tar-

       get thread supplied to pthread_exit(3)) into  the  location

       pointed  to by *retval.  If the target thread was canceled,

       then PTHREAD_CANCELED is placed in *retval.



       If multiple threads simultaneously try  to  join  with  the

       same  thread,  the  results  are  undefined.  If the thread

       calling pthread_join() is canceled, then the target  thread

       will remain joinable (i.e., it will not be detached).



RETURN VALUE

       On  success, pthread_join() returns 0; on error, it returns

       an error number.

解锁开锁

NAME

       pthread_mutex_lock

       pthread_mutex_unlock - lock and unlock a mutex



SYNOPSIS

       #include <pthread.h>



       int pthread_mutex_lock(pthread_mutex_t *mutex);

       int pthread_mutex_unlock(pthread_mutex_t *mutex);

初始化锁,销毁锁

NAME

       pthread_mutex_destroy,  pthread_mutex_init  -  destroy  and initialize a mutex



SYNOPSIS

       #include <pthread.h>



       int pthread_mutex_destroy(pthread_mutex_t *mutex);

       int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

代码

/*************************************************************************

  > File Name: ticket.c

  > Author: KrisChou

  > Mail:[email protected] 

  > Created Time: Mon 25 Aug 2014 07:40:38 PM CST

 ************************************************************************/



#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <pthread.h>



int ticket_cnt = 20;     /* 共有20张票 */

typedef struct tag

{

    int s_id;

    pthread_mutex_t *s_p;

}DATA,*pDATA;



void* handler(void *arg )

{

    int id = ((pDATA)arg)->s_id;

    pthread_mutex_t *p_mutex = ((pDATA)arg)-> s_p;

    printf("a window on !: %d \n", id);

    while(1)

    {

        pthread_mutex_lock(p_mutex);

        if(ticket_cnt == 0)

        {

            printf("ticket out! \n");

            pthread_mutex_unlock(p_mutex);

            free((pDATA)arg);

            return (void*)0;

        }

        --ticket_cnt;

        sleep(rand()%3 + 1);

        printf("window: %d : a ticket sold. left : %d \n", id,ticket_cnt );

        pthread_mutex_unlock(p_mutex);

        sleep(rand() % 3 + 1); /* 如果不sleep,锁会一直被这个执行完的线程所占据 */



    }

}



int main(int argc, char *argv[])

{

    srand(getpid());

    pthread_mutex_t mutex;

    pthread_mutex_init(&mutex, NULL);

    int thd_cnt = atoi(argv[1]); /* 从命令行输入卖票窗口数 */

    pthread_t *tds = (pthread_t*)calloc(thd_cnt,sizeof(pthread_t));

    int index;

    for(index = 0; index < thd_cnt; index++ )

    {

        pDATA p = (pDATA)calloc(1,sizeof(DATA));

        p->s_id = index;

        p->s_p = &mutex;

        pthread_create(tds + index , NULL,handler,(void*)p);

    }

    printf("joining...\n");

    for(index = 0; index < thd_cnt; index++)

    {

        pthread_join(tds[index],NULL);

    }

    pthread_mutex_destroy(&mutex);

    return 0;

}

编译运行:

[purple@localhost review]$ gcc ticket.c -lpthread

[purple@localhost review]$ ./a.out 5

joining...

a window on !: 2

a window on !: 3

a window on !: 4

a window on !: 1

a window on !: 0

window: 2 : a ticket sold. left : 19

window: 3 : a ticket sold. left : 18

window: 4 : a ticket sold. left : 17

window: 1 : a ticket sold. left : 16

window: 0 : a ticket sold. left : 15

window: 2 : a ticket sold. left : 14

window: 3 : a ticket sold. left : 13

window: 4 : a ticket sold. left : 12

window: 1 : a ticket sold. left : 11

window: 0 : a ticket sold. left : 10

window: 2 : a ticket sold. left : 9

window: 3 : a ticket sold. left : 8

window: 4 : a ticket sold. left : 7

window: 1 : a ticket sold. left : 6

window: 0 : a ticket sold. left : 5

window: 2 : a ticket sold. left : 4

window: 3 : a ticket sold. left : 3

window: 4 : a ticket sold. left : 2

window: 1 : a ticket sold. left : 1

window: 0 : a ticket sold. left : 0

ticket out!

ticket out!

ticket out!

ticket out!

ticket out!

干货

如果有一个整型参数 a 需要在创建线程时将其传递给线程,那么以下两种传值方式,实际上是由区别的。来看代码:

方式1:

void* handler(void *arg)

{

    int val=*(int*)arg;

    printf("from main: %d\n",val);

    pthread_exit((void*)"hello world");

}

int main()

{

    pthread_t thd;

    int a=12345;

    pthread_create(&thd,NULL,handler,(void*)&a);

    printf("thd: %x\n",thd);

    pthread_join(thd,(void*)&ret);

    return 0;

}

方式2:

void* handler(void *arg)

{

    int val=(int)arg;

    printf("from main: %d\n",val);

    pthread_exit((void*)"hello world");

}

int main()

{

    pthread_t thd;

    int a=12345;

    pthread_create(&thd,NULL,handler,(void*)a);

    printf("thd: %x\n",thd);

    pthread_join(thd,(void*)&ret);

    return 0;

}

对于方式1,传给handler的参数是a的地址,如果a的值之后在主线程里会发生变化,那么传给handler的数值a可能就不是原来我们想传的那个了。

而对于方式2,由于是值传递,我们当时想传什么,传到handler中的就一定是什么。

由此可见,虽然方式1节省了存储空间,但是同样也容易发生错误。

你可能感兴趣的:(linux)