循序渐进学unix——上机记录(八),Thread

本次上机主题为线程。一个程序可以包含多个进程,而一个进程又可以创建多个线程,每个线程都共享此进程的上下文环境。

在unix下使用gcc编译带有线程操作的程序时需要加上 -pthread选项。

基本的线程函数:

#include <pthread.h>

创建线程:后两个参数为待调用的函数及传递的参数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
在进程中等待相应线程的结束:

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

1,创建一个能实现两数相加的线程,使用3个线程实现(a + b) * (c + d)/(e + f)。为此,我们使用一个结构体传递加数及结果:

typedef struct _Calcul { float op1, op2, result; } Calcul;

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>

typedef struct _Calcul{ float op1, op2, result;}Calcul;
void somme(Calcul* calcul)
{
	calcul->result = calcul->op1 + calcul->op2;
}
 
void main()
{
	int val_return;
	int **res1, res2, res3;
	pthread_t ptr1, ptr2, ptr3;
	Calcul calcul1, calcul2, calcul3;
	calcul1.op1=1;
	calcul1.op2=2;
	calcul2.op1=3;
        calcul2.op2=4;
	calcul3.op1=5;
        calcul3.op2=16;

	if( (val_return=pthread_create(&ptr1, NULL, (void*)somme, (void*)(&calcul1) )) != 0)
	{	
		perror("pthread_create");exit(1);
	}
	if( (val_return=pthread_create(&ptr2, NULL, (void*)somme, (void*)(&calcul2) )) != 0)
	{	
		perror("pthread_create");exit(1);
	}
	if( (val_return=pthread_create(&ptr3, NULL, (void*)somme, (void*)(&calcul3) )) != 0)
	{	
		perror("pthread_create");exit(1);
	}
	pthread_join( ptr1, NULL);//(void**)res1);
	pthread_join( ptr2, NULL);//(void**)res1);
	pthread_join( ptr3, NULL);//(void**)res1);
	printf("(1+2)*(3+4)/(5+16)=%f\n", calcul1.result * calcul2.result / calcul3.result);
} 

2,使用互斥(mutex)实现对共享资源的访问,涉及到的函数有:

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

int pthread_mutex_destroy(pthread_mutex_t *mutex);

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex); 

关于互斥,在这里就不详解了。总之如果有多个线程想要访问同一个资源(比如文件)的话,那么每个线程在访问共享资源之前都应该调用pthread_mutex_lock,成功返回后就好比给共享资源加了一把锁,其他的线程在调用这个函数时会被卡住,直到此进程将资源解锁:pthread_mutex_unlock。当然init和destroy分别用于在使用前初始化和用完摧毁这一互斥。

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void ecrire( pthread_mutex_t * mutex)
{
	FILE* fd;
	
	while(1)
	{
		pthread_mutex_lock(mutex);//c'est préférable de mettre les opération dans le corps de mutex
			//fd = open("verrou.txt", O_WRONLY | O_CREAT);
			fd = fopen("verrou.txt", "w");
			if( fd==NULL ){perror("open");exit(errno);}
			fputs("Je suis la fonction ecrire!", fd);
			printf("Pthread ecrire : vient d'écrire une phrase...\n");
			fclose(fd);
		pthread_mutex_unlock(mutex);
		sleep(10);
	}
}

void lire( pthread_mutex_t * mutex)
{
	FILE* fd;
	char msg[50];
	while(1)
	{
		pthread_mutex_lock(mutex);
			fd = fopen("verrou.txt", "r");
			if( fd==NULL ){perror("open");exit(errno);}
			fgets( msg, 49, fd);
			fclose(fd);
		pthread_mutex_unlock(mutex);
		printf("Pthread lire : %s\n", msg);
		sleep(5);
	}
}

pthread_mutex_t mutex;

 
void main()
{
	int val_return;
	
	pthread_t ptr1, ptr2;
	pthread_mutex_init(&mutex, NULL);
	//mutex = PTHREAD_MUTEX_INITIALIZER;
	if( (val_return=pthread_create(&ptr1, NULL, (void*)ecrire, (void*)(&mutex) )) != 0)
	{	
		perror("pthread_create");exit(1);
	}
	if( (val_return=pthread_create(&ptr2, NULL, (void*)lire, (void*)(&mutex) )) != 0)
	{	
		perror("pthread_create");exit(1);
	}
	
	pthread_join( ptr1, NULL);//Si le proc termine, les threads sont aussi terminés
	pthread_join( ptr2, NULL);//(void**)res1);
	
} 


3,线程间的同步:barrier。

有这样一系列barrier函数可以在线程内部实现线程间的同步:

pthread_barrier_t barrier;
pthread_barrier_init(&barrier, NULL, THREAD_NUM);// Init the barrier with a number.
pthread_barrier_wait(&barrier);//The calling thread can continue only if there are THREAD_NUM threads who call this method.
pthread_barrier_destroy(&barrier);

简单地说,假如我们设置一个代表3个线程的barrier,并在3个线程中分别调用pthread_barrier_wait,那么只有当3个进程全部都执行到调用此函数的那行时,这3个线程才能继续向下进行。当第3个线程还没有到达此处时,前两个调用wait的线程都会被卡在那里,等待。


/*
The barrier is a way to synchronise threads during their executions,
while pthread_join(), which is called in the body of the process,
only synchronize the end of threads.

pthread_barrier_t barrier;
pthread_barrier_init(&barrier, NULL, THREAD_NUM);// Init the barrier with a number.
pthread_barrier_wait(&barrier);//The calling thread can continue only if there are
				THREAD_NUM threads who call this method.
pthread_barrier_destroy(&barrier);
*/

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define THREAD_NUM 5

pthread_barrier_t barrier;

void travailler( )
{
	int duree = ((int)random())%5+1;
	int threadid=pthread_self();
	printf("Pthread %d a une tâche de %d seconds.\n", threadid, duree);
	int i = 0;
	for(;i<duree;i++)
	{
		//If we put wait here, when a thread terminates, all others will be 
		//suspended, because there will nerver be enough threads who call wait()
		//pthread_barrier_wait(&barrier);
		printf("Pthread %d, second %d.\n", threadid, i);
		sleep(1);
	}
	pthread_barrier_wait(&barrier);
	printf("Pthread %d termine.\n", threadid);
}


void main()
{
	int val_return;
	pthread_t ptrs[THREAD_NUM];
	pthread_barrier_init(&barrier, NULL, THREAD_NUM);
	int i = 0;
	for(;i<THREAD_NUM;i++)
	{
		if( (val_return=pthread_create(ptrs+i, NULL, (void*)travailler, NULL)) != 0)
		{	
			perror("pthread_create");exit(1);
		}
	}
	
	for(i=0;i<THREAD_NUM;i++)
	{
		pthread_join( ptrs[i], NULL);//Si le proc termine, les threads sont aussi terminés
		printf("Join thread %d .\n", i);
	}
	//pthread_barrier_destroy(&barrier);

} 


猜你喜欢

转载自blog.csdn.net/tangwing/article/details/8425541