进程:是cpu分配资源的最小单位
线程:是操作系统能够进行运算调度的最小单位,被包含在进程之中,是进程中的实际运作单位
进程只是维护程序所需的资源,线程才是真正的执行体.所以一个进程至少包含一个线程.
一个进程的所有信息对该进程的所有线程都是共享的

每个线程都含有表示执行环境所必须的信息(非共享的 )
1)线程id
4) errno变量
5) 信号屏蔽字
6) 调度优先级
进程id在整个系统是唯一的,但线程id不同,只在他所属进程上下文中才有意义.
进程id使用pid-t数据类型表示,是一个非负整数.
线程id是用pthread_t数据类型表示,实现的时候用一个结构来代表pthread_t数据类型,所以可移植操作系统实现不能把他作为整数处理,

用结构表示pthread_t数据类型,我们可以通过pthread_self(获取线程id)pthread_equal(比较是否相等)


- #include
- #include
- int main()
- {
- pthread_t tid;
- tid=pthread_self();
- printf("tid=%d.....\n",tid);
- if(pthread_equal(tid,pthread_self()))
- {
- printf("equal............\n");
- }
- else{
- printf("no equal......\n");
- }
- return 0;
- }
-
- #include
-
- int pthread_create(pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *),
- void *arg );
- 功能:
- 创建一个线程。
- 参数:
- thread:线程标识符地址。
- attr:线程属性结构体地址,通常设置为 NULL。
- start_routine:线程函数的入口地址。
- arg:传给线程函数的参数。
- 返回值:
- 成功:0
- 失败:非 0
- #include
- #include
- #include
- void* fun(void *arg)
- {
- pthread_t ntid;
- printf("fun:%d\n",pthread_self());
- printf("pthread......run......\n");
- return (void*)0;
- }
- int main()
- {
- pthread_t tid;
-
- pid_t pid;
- pthread_create(&tid,NULL,fun,0);
- sleep(2);//主线程需要休眠,否则新线程创建不出来就退出了
- tid=pthread_self();
- printf("main:%d,%d\n",tid,getpid());
-
- return 0;
- }
任意线程调用exit.和_exit会使整个进程终止
单个线程可以通过3种方式退出(在进程不终止的情况下)
- #include
-
- void pthread_exit(void *retval);
- 功能:
- 退出调用线程。一个进程中的多个线程是共享该进程的数据段,因此,通常线程退出后所占用的资源并不会释放。
- 参数:
- retval:存储线程退出状态的指针。
- 返回值:无
-
- #include
-
- int pthread_join(pthread_t thread, void **retval);
- 功能:
- 等待线程结束(此函数会阻塞),并回收线程资源,类似进程的 wait() 函数。如果线程已经结束,那么该函数会立即返回。
- 参数:
- thread:被等待的线程号。
- retval:用来存储线程退出状态的指针的地址。
- 返回值:
- 成功:0
- 失败:非 0

如果对返回值不感兴趣就将rval_ptr设为null,不获取线程的终止状态
- #include
- #include
- W>void* fun1(void*arg)
- {
- printf("fun1....return ......\n");
- return (void*)123;
- }
- W>void * fun2(void *arg)
- {
- printf("fun2......exit...........\n");
- pthread_exit((void*)2);
- }
- int main()
- {
- pthread_t tid1;
- pthread_t tid2;
- //状态码
- void *ret;
-
- //创建线程
- pthread_create(&tid1,NULL,fun1,0);
- pthread_create(&tid2,NULL,fun2,0);
-
- //等待结束
- pthread_join(tid1,&ret);
- printf("thread 1 return.....%ld\n",(long)ret);
- pthread_join(tid2,&ret);
- printf("thread 2 exit.......%ld\n",(long)ret);
-
- return 0;
- }

变量(分配在栈上)作为pthread_exit的参数时出现问题
- #include
- #include
- #include
- struct data {
- int a,b,c,d;
- };
- void printfdata(char*s,struct data*fd)
- {
- printf("%s",s);
- printf("struct at 0x%lx\n",(long)fd);
- printf("fd->a:%d\n",fd->a);
- printf("fd->b:%d\n",fd->b);
- printf("fd->c:%d\n",fd->c);
- printf("fd->d:%d\n",fd->d);
-
- }
- void *fun1(void*arg)
- {
- struct data fd={1,2,3,4};
- printfdata("thread 1\n",&fd);
- pthread_exit((void*)&fd);
- }
- void *fun2(void *arg)
- {
- printf("thread 2:id is %lu\n",pthread_self());
- pthread_exit((void*)0);
- }
- int main()
- {
-
- pthread_t tid1;
- pthread_t tid2;
- struct data *fd;
- //创建线程
- int ret= pthread_create(&tid1,NULL,fun1,NULL);
- if(ret!=0)
- {
- printf("thread 1 error..........\n");
- return 1;
- }
- ret=pthread_join(tid1,(void *)&fd);
- if(ret!=0)
- {
- printf("join.........error\n");
- return 1;
- };
- sleep(2);
- printf("starting second thread.....\n");
- pthread_create(&tid2,NULL,fun2,NULL);
- sleep(1);
- printfdata("second:\n",fd);
- return 0;
- }

线程可以调用pthread_cancel()函数来请求取消同一进程的其他进程(只是请求并不一定取消)

一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。
不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
-
- #include
-
- int pthread_detach(pthread_t thread);
- 功能:
- 使调用线程与当前进程分离,分离后不代表此线程不依赖与当前进程,
- 线程分离的目的是将线程资源的回收工作交由系统自动来完成,也就是说当
- 被分离的线程结束之后,系统会自动回收它的资源。所以,此函数不会阻塞。
- 参数:
- thread:线程号。
- 返回值:
- 成功:0
- 失败:非0
- #include
- #include
- #include
- W>void*fun(void*arg)
- {
- printf("cccccccccccccccc\n");
- pthread_exit((void*)1);
- }
- int main()
- {
- pthread_t tid;
- pthread_create(&tid,NULL,fun,NULL);
- sleep(2);//保证线程创建成功
- // 设置分离
- pthread_detach(tid);
-
- return 0;
两个或两个以上线程在访问同一种资源按先后顺序完成指定任务
如果两个或两个以上线程不同步会出现数据错误
使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的。
例子
- #include
- #include
- #include
- void *fun1(void*arg)
- {
- for(int i='A';i<='Z';i++)
- {
- printf("%c",i);
- fflush(stdout);
- usleep(100000);
- }
- pthread_exit((void*)1);
- }
- W>void*fun2(void*arg)
- {
- for(int i='a';i<='z';i++)
- {
- printf("%c",i);
- fflush(stdout);
- usleep(100000);
- }
- pthread_exit((void*)2);
- }
- int main()
- {
- pthread_t tid1;
- pthread_t tid2;
-
- pthread_create(&tid1,NULL,fun1,NULL);
- pthread_create(&tid2,NULL,fun2,NULL);
- sleep(2);
- printf("\n");
- pthread_detach(tid1);
- pthread_detach(tid2);
- return 0;
- }
为了避免数据发生错误
对公共资源加锁,在该线程访问时,禁止其他进程使用,完成后解锁

- #include
-
- int pthread_mutex_init(pthread_mutex_t *restrict mutex,
- const pthread_mutexattr_t *restrict attr);
- 功能:
- 初始化一个互斥锁。
- 参数:
- mutex:互斥锁地址。类型是 pthread_mutex_t 。
- attr:设置互斥量的属性,通常可采用默认属性,即可将 attr 设为 NULL。
-
- 可以使用宏 PTHREAD_MUTEX_INITIALIZER 静态初始化互斥锁,比如:
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
- 这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_mutex_init() 来完成动态初始化,不同之处在于 PTHREAD_MUTEX_INITIALIZER 宏不进行错误检查。
-
- 返回值:
- 成功:0,成功申请的锁默认是打开的。
- 失败:非 0 错误码
-
- #include
-
- int pthread_mutex_lock(pthread_mutex_t *mutex);
- 功能:
- 对互斥锁上锁,若互斥锁已经上锁,则调用者阻塞,直到互斥锁解锁后再上锁。
- 参数:
- mutex:互斥锁地址。
- 返回值:
- 成功:0
- 失败:非 0 错误码
-
- int pthread_mutex_trylock(pthread_mutex_t *mutex);
- 调用该函数时,若互斥锁未加锁,则上锁,返回 0;
- 若互斥锁已加锁,则函数直接返回失败,即 EBUSY。
-
- #include
-
- int pthread_mutex_destroy(pthread_mutex_t *mutex);
- 功能:
- 销毁指定的一个互斥锁。互斥锁在使用完毕后,必须要对互斥锁进行销毁,以释放资源。
- 参数:
- mutex:互斥锁地址。
- 返回值:
- 成功:0
- 失败:非 0 错误码
-
- #include
-
- int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 功能:
- 对指定的互斥锁解锁。
- 参数:
- mutex:互斥锁地址。
- 返回值:
- 成功:0
- 失败:非0错误码
-
- pthread_mutex_t mutex; //互斥锁
-
- // 打印机
- void printer(char *str)
- {
- pthread_mutex_lock(&mutex); //上锁
- while (*str != '\0')
- {
- putchar(*str);
- fflush(stdout);
- str++;
- sleep(1);
- }
- printf("\n");
- pthread_mutex_unlock(&mutex); //解锁
- }
-
- // 线程一
- void *thread_fun_1(void *arg)
- {
- char *str = "hello";
- printer(str); //打印
- }
-
- // 线程二
- void *thread_fun_2(void *arg)
- {
- char *str = "world";
- printer(str); //打印
- }
-
- int main(void)
- {
- pthread_t tid1, tid2;
-
- pthread_mutex_init(&mutex, NULL); //初始化互斥锁
-
- // 创建 2 个线程
- pthread_create(&tid1, NULL, thread_fun_1, NULL);
- pthread_create(&tid2, NULL, thread_fun_2, NULL);
-
- // 等待线程结束,回收其资源
- pthread_join(tid1, NULL);
- pthread_join(tid2, NULL);
-
- pthread_mutex_destroy(&mutex); //销毁互斥锁
-
- return 0;
- }



死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,永远在互相等待
破坏死锁的四个必要条件中的一个或多个来预防死锁。
和预防死锁的区别就是,在资源动态分配过程中,用某种方式防止系统进入不安全的状态。
运行时出现死锁,能及时发现死锁,把程序解脱出来
发生死锁后,解脱进程,通常撤销进程,回收资源,再分配给正处于阻塞状态的进程。
破坏请求和保持条件
协议1:
所有进程开始前,必须一次性地申请所需的所有资源,这样运行期间就不会再提出资源要求,破坏了请求条件,即使有一种资源不能满足需求,也不会给它分配正在空闲的资源,这样它就没有资源,就破坏了保持条件,从而预防死锁的发生。
协议2:
允许一个进程只获得初期的资源就开始运行,然后再把运行完的资源释放出来。然后再请求新的资源。
破坏不可抢占条件
当一个已经保持了某种不可抢占资源的进程,提出新资源请求不能被满足时,它必须释放已经保持的所有资源,以后需要时再重新申请。
破坏循环等待条件
对系统中的所有资源类型进行线性排序,然后规定每个进程必须按序列号递增的顺序请求资源。假如进程请求到了一些序列号较高的资源,然后有请求一个序列较低的资源时,必须先释放相同和更高序号的资源后才能申请低序号的资源。多个同类资源必须一起请求。