所有实例程序都由C语言编写
实测,可运行
实例一:
#include <stdio.h>
#include <pthread.h>
void thread(void)
{
int i;
for(i=0;i<3;i++)
printf("This is a pthread.\n");
}
int main(void)
{
pthread_t id;//声明变量
int i,ret;
ret=pthread_create(&id,NULL,(void *) thread,NULL); // 成功返回0,错误返回错误编号
if(ret!=0)
{
printf ("Create pthread error!\n");
exit (1);
}
for(i=0;i<3;i++)
{
printf("This is the main process.\n");
}
pthread_join(id,NULL);
return (0);
}
实例一分析:函数pthread_create用来创建一个线程,第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数,函数pthread_join用来等待一个线程的结束,第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。其中由于线程并发运行顺序的不确定性,会引起输出结果的随机性,这是由于线程争夺CPU资源造成的。属于并发引起的race condition.可以作为并发实例。
实例二:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
int count = 0;
int i = 0;
int j = 0;
int k = 0;
/*给i的值和count的值加1*/
void *modify_i_thread(void *data)
{
for(;;)
{
i++;
count++;
}
}
/*给j的值和count的值加1*/
void *modify_j_thread(void *data)
{
for(;;) {
j++;
count++;
}
}
/*给k的值和count的值加1*/
void *modify_k_thread(void *data)
{
for(;;) {
k++;
count++;
}
}
int main(void)
{
pthread_t pthid;
/*创建三个线程 */
pthread_create(&pthid, NULL, modify_i_thread, NULL);
pthread_create(&pthid, NULL, modify_j_thread, NULL);
pthread_create(&pthid, NULL, modify_k_thread, NULL);
sleep(1);
/*打印结果 */
printf("i = %d, j = %d, k= %d, count = %d\n", i, j, k, count);
printf("i+j+k=%d\n", i + j + k);
return 0;
}
实例二分析: 首先来看程序,程序很简单,就是创建了3个线程,第一个线程对i和count加1,第二个线程对j和count加1,第三个线程对k和count加1,i,j,k,count初始化都为0,这样的话,按照逻辑来说,最后i+j+k = count:仔细分析下创建的线程执行的操作,3个线程中都对count进行了++操作,++操作在C语言中看起来是一条语句,实际上编译后是3条语句,首先将count的值写入寄存器,然后对其进行加1操作,在接着将寄存器的值读出,保存在count中。
三个线程简称为A、B、C,如果A刚刚把count的值写入寄存器中,此时调度程序调度B线程开始运行,这个时候,B对count进行了N次加法操作,此时count = count+N,此时调度程序恢复执行A线程,那么此时A中保存的count的值却是是B线程执行前的值,此时,A再对count进行操作时,就是基于旧的值(其他线程对count进行操作前的值),而不是最新的值,所以count的值并不是我们期望中的值。
属于并发引起的数据竞争问题。(竞争count)
实例三:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex; //互斥锁
void *runodd(void *d)
{
int i=0;
for(i=1;;i+=2)
{
pthread_mutex_lock(&mutex);//上锁
printf("奇数:%d\n",i);
usleep(100);
pthread_mutex_unlock(&mutex);//解锁
}
}
void *runeven(void *d)
{
int i=0;
for(i=0;;i+=2)
{
pthread_mutex_lock(&mutex);
printf("偶数:%d\n",i);
usleep(100);
pthread_mutex_unlock(&mutex);
}
}
main()
{
pthread_t todd,teven; //定义两个线程
pthread_mutex_init(&m,0); //创建锁
pthread_create(&todd,0,runodd,0);
pthread_create(&teven,0,runeven,0);
sleep(5);
printf("外部强制停止todd线程\n");
pthread_cancel(todd);
pthread_join(todd,(void**)0); //pthread_join()函数,以阻塞的方式等待thread指定的线程结束
pthread_join(teven,(void**)0);
pthread_mutex_destroy(&mutex); //锁的释放
}
实例三分析: 属于并发引起的死锁问题,强制停止todd线程后,join函数还在以正常的状态等待,会导致teven线程一直死等。
实例四:
//假如我们要一直让thread1先执行减,thread2执行加,执行两个函数,顺序不确定的两个线程
#include <stdio.h>
#include <pthread.h>
int i=10;
void *func1(void *param)
{
while(1)
{
if(i>0)
{
i--;
printf("Thread 1::i is %d\n",i);
}else
{
break;
}
}
}
void *func2(void *param)
{
while(1)
{
if(i<10)
{
i++;
printf("Thread 2::i is %d\n",i);
}else
{
break;
}
}
}
int main()
{
pthread_t threads[2];
pthread_create(&threads[0],0,func1,0);
pthread_create(&threads[1],0,func2,0);
pthread_join(threads[0],0);
pthread_join(threads[1],0);
return 0;
}
实例四分析:两个函数,我们本想让函数一执行减法,函数二执行加法,串行下结果为10---1-----10,但是由于并行,会导致不可知数据,属于并发引起的数据竞争错误。
实例五:
#include<unistd.h>
#include <stdio.h>
#include<stdlib.h>
int x;
int One()
{
int y,z;
x=1;
y=0;
if(x>=1)
{
y=y+1;
}
z=y;
return (z);//第一个函数执行结果z=1
}
int Two()
{
int y,z;
x=0;
y=0;
if(x<1)
{
y=y+2;
}
z=y;
return (z);//第二个函数执行结果z=2
}
void main()
{
int pid;
pid=fork();//,创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
if ( pid == 0 ) //返回0证明创建子进程成功
{
One();
}
else {
Two();
}
}
实例五分析:fork()函数作用:当程序调用fork()函数并返回成功之后,程序就将变成两个进程,调用fork()者为父进程,后来生成者为子进程。
若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回,因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
属于并发引起的共享数据竞争的问题。