题目

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

思路

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

函数原型

创建线程:

  1. NAME
  2. pthread_create - create a new thread
  3.  
  4. SYNOPSIS
  5. #include <pthread.h>
  6.  
  7. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  8. void *(*start_routine) (void *), void *arg);
  9.  
  10. Compile and link with -pthread.

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

  1. NAME
  2. pthread_join - join with a terminated thread
  3.  
  4. SYNOPSIS
  5. #include <pthread.h>
  6.  
  7. int pthread_join(pthread_t thread, void **retval);
  8.  
  9. Compile and link with -pthread.
  10.  
  11. DESCRIPTION
  12. The pthread_join() function waits for the thread specified
  13. by thread to terminate. If that thread has already termi-
  14. nated, then pthread_join() returns immediately. The thread
  15. specified by thread must be joinable.
  16.  
  17. If retval is not NULL, then pthread_join() copies the exit
  18. status of the target thread (i.e., the value that the tar-
  19. get thread supplied to pthread_exit(3)) into the location
  20. pointed to by *retval. If the target thread was canceled,
  21. then PTHREAD_CANCELED is placed in *retval.
  22.  
  23. If multiple threads simultaneously try to join with the
  24. same thread, the results are undefined. If the thread
  25. calling pthread_join() is canceled, then the target thread
  26. will remain joinable (i.e., it will not be detached).
  27.  
  28. RETURN VALUE
  29. On success, pthread_join() returns 0; on error, it returns
  30. an error number.

解锁开锁

  1. NAME
  2. pthread_mutex_lock
  3. pthread_mutex_unlock - lock and unlock a mutex
  4.  
  5. SYNOPSIS
  6. #include <pthread.h>
  7.  
  8. int pthread_mutex_lock(pthread_mutex_t *mutex);
  9. int pthread_mutex_unlock(pthread_mutex_t *mutex);

初始化锁,销毁锁

  1. NAME
  2. pthread_mutex_destroy, pthread_mutex_init - destroy and initialize a mutex
  3.  
  4. SYNOPSIS
  5. #include <pthread.h>
  6.  
  7. int pthread_mutex_destroy(pthread_mutex_t *mutex);
  8. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

代码

  1. /*************************************************************************
  2. > File Name: ticket.c
  3. > Author: KrisChou
  4. > Mail:zhoujx0219@163.com
  5. > Created Time: Mon 25 Aug 2014 07:40:38 PM CST
  6. ************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <pthread.h>
  12.  
  13. int ticket_cnt = 20; /* 共有20张票 */
  14. typedef struct tag
  15. {
  16. int s_id;
  17. pthread_mutex_t *s_p;
  18. }DATA,*pDATA;
  19.  
  20. void* handler(void *arg )
  21. {
  22. int id = ((pDATA)arg)->s_id;
  23. pthread_mutex_t *p_mutex = ((pDATA)arg)-> s_p;
  24. printf("a window on !: %d \n", id);
  25. while(1)
  26. {
  27. pthread_mutex_lock(p_mutex);
  28. if(ticket_cnt == 0)
  29. {
  30. printf("ticket out! \n");
  31. pthread_mutex_unlock(p_mutex);
  32. free((pDATA)arg);
  33. return (void*)0;
  34. }
  35. --ticket_cnt;
  36. sleep(rand()%3 + 1);
  37. printf("window: %d : a ticket sold. left : %d \n", id,ticket_cnt );
  38. pthread_mutex_unlock(p_mutex);
  39. sleep(rand() % 3 + 1); /* 如果不sleep,锁会一直被这个执行完的线程所占据 */
  40.  
  41. }
  42. }
  43.  
  44. int main(int argc, char *argv[])
  45. {
  46. srand(getpid());
  47. pthread_mutex_t mutex;
  48. pthread_mutex_init(&mutex, NULL);
  49. int thd_cnt = atoi(argv[1]); /* 从命令行输入卖票窗口数 */
  50. pthread_t *tds = (pthread_t*)calloc(thd_cnt,sizeof(pthread_t));
  51. int index;
  52. for(index = 0; index < thd_cnt; index++ )
  53. {
  54. pDATA p = (pDATA)calloc(1,sizeof(DATA));
  55. p->s_id = index;
  56. p->s_p = &mutex;
  57. pthread_create(tds + index , NULL,handler,(void*)p);
  58. }
  59. printf("joining...\n");
  60. for(index = 0; index < thd_cnt; index++)
  61. {
  62. pthread_join(tds[index],NULL);
  63. }
  64. pthread_mutex_destroy(&mutex);
  65. return 0;
  66. }

编译运行:

  1. [purple@localhost review]$ gcc ticket.c -lpthread
  2. [purple@localhost review]$ ./a.out 5
  3. joining...
  4. a window on !: 2
  5. a window on !: 3
  6. a window on !: 4
  7. a window on !: 1
  8. a window on !: 0
  9. window: 2 : a ticket sold. left : 19
  10. window: 3 : a ticket sold. left : 18
  11. window: 4 : a ticket sold. left : 17
  12. window: 1 : a ticket sold. left : 16
  13. window: 0 : a ticket sold. left : 15
  14. window: 2 : a ticket sold. left : 14
  15. window: 3 : a ticket sold. left : 13
  16. window: 4 : a ticket sold. left : 12
  17. window: 1 : a ticket sold. left : 11
  18. window: 0 : a ticket sold. left : 10
  19. window: 2 : a ticket sold. left : 9
  20. window: 3 : a ticket sold. left : 8
  21. window: 4 : a ticket sold. left : 7
  22. window: 1 : a ticket sold. left : 6
  23. window: 0 : a ticket sold. left : 5
  24. window: 2 : a ticket sold. left : 4
  25. window: 3 : a ticket sold. left : 3
  26. window: 4 : a ticket sold. left : 2
  27. window: 1 : a ticket sold. left : 1
  28. window: 0 : a ticket sold. left : 0
  29. ticket out!
  30. ticket out!
  31. ticket out!
  32. ticket out!
  33. ticket out!

干货

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

方式1:

  1. void* handler(void *arg)
  2. {
  3. int val=*(int*)arg;
  4. printf("from main: %d\n",val);
  5. pthread_exit((void*)"hello world");
  6. }
  7. int main()
  8. {
  9. pthread_t thd;
  10. int a=12345;
  11. pthread_create(&thd,NULL,handler,(void*)&a);
  12. printf("thd: %x\n",thd);
  13. pthread_join(thd,(void*)&ret);
  14. return 0;
  15. }

方式2:

  1. void* handler(void *arg)
  2. {
  3. int val=(int)arg;
  4. printf("from main: %d\n",val);
  5. pthread_exit((void*)"hello world");
  6. }
  7. int main()
  8. {
  9. pthread_t thd;
  10. int a=12345;
  11. pthread_create(&thd,NULL,handler,(void*)a);
  12. printf("thd: %x\n",thd);
  13. pthread_join(thd,(void*)&ret);
  14. return 0;
  15. }

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

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

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

Linux多线程之互斥的更多相关文章

  1. Linux多线程——使用互斥量同步线程

    前文再续,书接上一回,在上一篇文章: Linux多线程——使用信号量同步线程中,我们留下了一个如何使用互斥量来进行线程同步的问题,本文将会给出互斥量的详细解说,并用一个互斥量解决上一篇文章中,要使用两 ...

  2. Linux多线程--使用互斥量同步线程【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10875883 前文再续,书接上一回,在上一篇文章:Linux多线程——使用信号量同步线程中, ...

  3. Linux多线程--使用信号量同步线程【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10813469 信号量.同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过 ...

  4. [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程

    一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...

  5. Linux多线程(三)(同步互斥)

    1. 线程的同步与互斥 1.1. 线程的互斥 在Posix Thread中定义了一套专门用于线程互斥的mutex函数.mutex是一种简单的加锁的方法来控制对共享资源的存取,这个互斥锁只有两种状态(上 ...

  6. Linux多线程服务端编程一些总结

    能接触这本书是因为上一个项目是用c++开发基于Linux的消息服务器,公司没有使用第三方的网络库,卷起袖子就开撸了.个人因为从业经验较短,主 要负责的是业务方面的编码.本着兴趣自己找了这本书.拿到书就 ...

  7. linux多线程同步pthread_cond_XXX条件变量的理解

    在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-- ...

  8. Linux多线程编程和Linux 2.6下的NPTL

    Linux多线程编程和Linux 2.6下的NPTL 在Linux 上,从内核角度而言,基本没有什么线程和进程的区别--大家都是进程.一个进程的多个线程只是多个特殊的进程他们虽然有各自的进程描述结构, ...

  9. linux多线程编程(转)

    原文地址:http://www.cnblogs.com/BiffoLee/archive/2011/11/18/2254540.html 1.Linux“线程” 进程与线程之间是有区别的,不过Linu ...

随机推荐

  1. android开发系列之多线程

    今天在这篇博客里面,我只想谈谈自己对程序开发里面避无可避的一个问题-多线程的一些看法与思考. 其实说到多线程这个名称相信只要接触过软件这个行业的人都已经耳熟能详了,但是如果被问到到底什么才是多线程呢? ...

  2. android开发系列之gradle认识

    后面的系列博客,我将会写一写自己这段时间对于android的学习.认识.体会,希望能够与大家分享. 相信大家从ADT开发切换到android studio最大.最直观的变化就是gradle,因为在an ...

  3. UITableView 表视图编辑

    UITableViewController(表视图控制器)继承自UIViewController,自带一个tableView self.view不是UIView而是UITableView dataso ...

  4. 在windows上使用symfony创建简易的CMS系统(一)

    http://blog.csdn.net/kunshan_shenbin/article/details/7164675 参考自:http://xsymfony.801.cxne.net/forum. ...

  5. [转]ubuntu 14.04 系统设置不见了

    [转]ubuntu 14.04 系统设置不见了 http://blog.sina.com.cn/s/blog_6c9d65a10101i0i7.html 不知道删除什么了,系统设置不见了! 我在终端运 ...

  6. 006--VS2013 C++ 加载其他格式图片,并显示半透明化

    //--------------------------------------------MyPaint() 函数------------------------------------------ ...

  7. Daily Scrum 12.7

    摘要:本次会议主要是为了分配任务.我们对于各自将要进行的任务进行了讨论,并最终确定下了我们每个人Beta版本将要进行的任务.因为vs中任务的编写在此次会议之后,所以迭代时直接填写了已完成时间. Tas ...

  8. 如何使用css和jquery控制文章标题字数?

    如何使用css控制文章标题字数? 最佳答案 控制文章标题字数,不是动态网页的专利,如果静态页面使用CSS样式,也可以实现相同的效果! 看这个例子,你们可以复制到记事本保存为HTML文件看效果! < ...

  9. 多种方法实现H5网页图片动画效果;

    在web开发中,GIF动画效果是随处可见,比如常见的loading加载.人物奔跑的gif图片等等,那么这些都是怎么实现的呢?其实实现的原理很简单,简而言之,这些所谓的动画都是一帧一帧的图片经过一段时间 ...

  10. AxMicrosoft.Office.Interop.Owc11.AxSpreadsheet控件在C#中的引用

    这几天要是用AxMicrosoft.Office.Interop.Owc11.AxSpreadsheet控件做查询,发现一系列问题,一点点记录下来吧,以备后查: 第一.相关属性:http://www. ...