《Unix/Linux系统编程》第七周学习笔记

并发进程

线程管理函数

pthread_create()

int pthread_create (pthread_t *pthread_id, pthread_attr_t *attr, void *(*func)(void *), void *arg);

  • 如果成功则返回0,如果失败则返回错误代码。pthread_create()函数的参数为。
1.pthread_id是指向pthread_t类型变量的指针。它会被操作系统内核分配的唯一线程ID填充。在POSIX中,pthread_t是一种不透明的类型。
程序员应该不知道不透明对象的内容,因为它可能取决于实现情况。线程可通过pthread_self()函数获得自己的ID。在 Linux 中,pthread_t
类型被定义为无符号长整型,因此线程ID可以打印为%lu。
2.attr是指向另一种不透明数据类型的指针,它指定线程属性,下面将对此进行更详细的说明。
3.func是要执行的新线程函数的入口地址。 arg是指向线程函数参数的指针,可写为:void *func(void *arg)。
4.attr参数
(1)定义一个pthread属性变量pthread_attr_t attr。
(2)用pthread_attr_init (&attr)初始化属性变量。
(3)设置属性变量并在pthread_create()调用中使用。
(4)必要时,通过pthread_attr_destroy (&attr)释放attr资源。
pthread_equal

int pthread_equal (pthread_t t1, pthread_t t2);

  • 如果是不同的线程,则返回0,否则返回非0。
pthread_exit()

int pthread_exit (void *status);

  • 进行显式终止,其中状态是线程的退出状态。通常,0退出值表示正常终止,非0值表示异常终止
pthread_join()

int pthread_join (pthread_t thread, void **status ptr);

  • 终止线程的退出状态以status_ptr返回。

实践一下(创建多线程同时计算数组的和完成矩阵的求和)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define N 4
int A[N][N], sum[N];
void *func(void *arg)
{
    int j, row;
    pthread_t tid = pthread_self(); // get thread ID number 
    row = (int)arg;	// get row number from arg
    printf("Thread %d [%lu] computes sum of row %d\n", row, tid, row); 
    for (j=0; j<N; j++)
    {
        sum[row] += A[row][j];
    }
    printf("Thread %d [%lu] done锟斤拷 sum[%d] = %d\n",row, tid, row, sum[row]);
    pthread_exit((void*)0); // thread exit: 0=normal termination
}

int main (int argc, char *argv[])
{
    pthread_t thread[N];	// thread IDs
    int i, j, r, total = 0;
    void *status;
    printf("Main: initialize A matrix\n",N);

    for (i=0; i<N; i++)
    {
        sum[i] = 0;
        for (j=0; j<N; j++)
        {
            A[i][j] = i*N + j + 1;
            printf("%4d" ,A[i][j]);
        }
    printf("\n");
    }
    printf("Main: create %d threads\n", N);
    for(i=0; i<N; i++)
    {
        pthread_create(&thread[i], NULL, func, (void *)i);
    }
    printf("Main: try to join with threads\n");
    for(i=0; i<N; i++) 
    {
        pthread_join(thread[i], &status);
        printf("Main: joined with %d [%lu]: status=%d\n",i, thread[i], (int)status);
    }
    printf("Main: compute and print total sum:"); 
    for (i=0; i<N; i++)
    {
        total += sum[i];
    }
    printf("tatal = %d\n", total); 
    pthread_exit(NULL);
}

线程同步

互斥量

Pthread提供许多可以用来同步线程的函数。其基本机制是使用一个可以被锁定和解锁的互斥量来保护每个临界区。一个线程如果想要进入临界区,
它首先尝试锁住相关的互斥量。如果互斥量没有加锁,那么这个线程可以立即进入,并且该互斥量被自动锁定以防止其他线程进入。如果互斥量已经
被加锁,则调用线程被阻塞,直到该互斥量被解锁。如果多个线程在等待同一个互斥量,当它被解锁时,这些等待的线程中只有一个被允许运行并
将互斥量重新锁定。这些互斥锁不是强制性的,而是由程序员来保证线程正确地使用它们。
与互斥量相关的主要函数调用如图所示

死锁预防

https://blog.csdn.net/qq_43672652/article/details/105409600

条件变量
  • 条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,
    主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等
    待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用
  • 当条件满足的时候,线程通常解锁并等待该条件发生变化,一旦另一个线程修改了环境变量,就会通知相应的环境
    变量唤醒一个或者多个被这个条件变量阻塞的线程。这些被唤醒的线程将重新上锁,并测试条件是否满足。一般来说条件
    变量被用于线程间的同步;当条件不满足的时候,允许其中的一个执行流挂起和等待
pthread_cond_init()函数               功能:初始化一个条件变量
pthread_cond_wait()函数             功能:阻塞等待一个条件变量
pthread_cond_timedwait()函数    功能:限时等待一个条件变量
pthread_cond_signal()函数          功能:唤醒至少一个阻塞在条件变量上的线程
pthread_cond_broadcast()函数    功能:唤醒全部阻塞在条件变量上的线程
pthread_cond_destroy()函数        功能:销毁一个条件变量
以上6个函数的返回值都是:成功返回0,失败直接返回错误号。
pthread_cond_t  类型,其本质是一个结构体。为简化理解,应用时可忽略其实现细节,简单当成整数看待。如:
pthread_cond_t  cond; 变量cond只有两种取值1、0。

信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。
信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明
它被占用,测试的线程要进入睡眠队列中,等待被唤醒。
https://www.cnblogs.com/linengier/p/9399880.html

Linux中的线程

https://blog.csdn.net/qq_22847457/article/details/89371217

实践一下。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
 
void *fun(void *arg)
{
	printf("I'm thread, Thread ID = %lu\n", pthread_self());
	return NULL;
}
 
int main(void)
{
	pthread_t tid;
 
	pthread_create(&tid, NULL, fun, NULL);
	sleep(1);      // 在多线程环境中,父线程终止,全部子线程被迫终止
	printf("I am main, my pid = %d\n", getpid());
 
	return 0;
}

实践

创建线程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NBUF 5
#define N 10
//shared global variab1es
int buf [NBUF];//circular buffers
int head, tail;//indices
int data;//number of full buffers
pthread_mutex_t mutex;//mutex lock
pthread_cond_t empty,full;//condition variables
int init(){
	head = tail = data = 0;
	pthread_mutex_init(&mutex,NULL);
	pthread_cond_init(&full,NULL);
	pthread_cond_init(&empty,NULL);
}
void *producer (){
	int i;
	pthread_t me = pthread_self() ;
	for (i=0; i<N; i++){ //try to put N items into buf[ ]
		pthread_mutex_lock(&mutex);//lock mutex
		if(data == NBUF) {
			printf("producer %lu: all bufs FULL: wait\n",me);
			pthread_cond_wait(&empty, &mutex);//wait
		}
		buf[head++] = i+1;//item = 1,2?.,N
		head %=NBUF;//circular bufs
		data++;//inc data by 1
		printf("producer %lu: data=%d value=%d\n",me,data,i+1);
		pthread_mutex_unlock(&mutex);//unlock mutex
		pthread_cond_signal(&full);//unblock a consumer?if any
	}
	printf("producer %lu: exit \n",me);
}
void *consumer(){
	int i, c;
	pthread_t me = pthread_self();
	for(i=0; i<N; i++){
		pthread_mutex_lock(&mutex);//lock mutex
		if(data == 0){
			printf ("consumer %lu: all bufs EMPTY : wait\n",me);
			pthread_cond_wait(&full,&mutex);//wait
		}
    	c=buf[tail++];//get an item
		tail%=NBUF;
		data--;//dec data by 1
		printf("consumer %lu: value=%d\n",me,c);
		pthread_mutex_unlock(&mutex);//unlock mutex
		pthread_cond_signal(&empty);//unblock a producer,if any
	}
	printf("consumer %lu: exit\n",me);
}
int main(){
	pthread_t pro, con;
	init();
	printf("main: create producer and consumer threads \n");
	pthread_create(&pro,NULL, producer,NULL);
	pthread_create (&con,NULL,consumer,NULL);
	printf("main: join with threads\n");
	pthread_join(pro,NULL);
	pthread_join(con,NULL);
	printf("main: exit\n");
}

线程快速排序

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct{
	int upperbound;
	int lowerbound;
}PARM;
#define N 10
int a[N]={5, 1, 6, 4, 7, 2, 9, 8, 0, 3};// unsorted data
int print(){//print current a[] contents
	int i;
	printf("[");
	for (i=0; i<N; i++)
		printf("%d ", a[i]);
	printf("]\n");
}
void *Qsort(void *aptr){
	PARM *ap, aleft, aright;
	int pivot, pivotIndex, left, right,temp;
	int upperbound,lowerbound;
	pthread_t me, leftThread, rightThread;
	me = pthread_self();
	ap = (PARM *)aptr;
	upperbound = ap->upperbound;
	lowerbound = ap->lowerbound;
	pivot = a[upperbound];//pick low pivot value
	left = lowerbound - 1;//scan index from left side
	right = upperbound;//scan index from right side
	if (lowerbound >= upperbound)
		pthread_exit (NULL);
	while (left < right){//partition loop
		do {left++;} while (a[left] < pivot);
		do {right--;} while(a[right]>pivot);
		if (left < right ) {
			temp = a[left];a[left]=a[right];a[right] = temp;
		}
	}
	print();
	pivotIndex = left;//put pivot back
	temp = a[pivotIndex] ;
	a[pivotIndex] = pivot;
	a[upperbound] = temp;
	//start the "recursive threads"
	aleft.upperbound = pivotIndex - 1;
	aleft.lowerbound = lowerbound;
	aright.upperbound = upperbound;
	aright.lowerbound = pivotIndex + 1;
	printf("%lu: create left and right threads\n", me) ;
	pthread_create(&leftThread, NULL, Qsort, (void * )&aleft);
	pthread_create(&rightThread, NULL, Qsort, (void *)&aright);
	//wait for left and right threads to finish
	pthread_join(leftThread, NULL);
	pthread_join(rightThread, NULL);
	printf("%lu: joined with left & right threads\n",me);
}
	int main(int argc, char *argv[]){
	PARM arg;
	int i, *array;
	pthread_t me, thread;
	me = pthread_self( );
	printf("main %lu: unsorted array = ", me);
	print();
	arg.upperbound = N-1;
	arg.lowerbound = 0 ;
	printf("main %lu create a thread to do QS\n" , me);
	pthread_create(&thread, NULL, Qsort, (void * ) &arg);//wait for Qs thread to finish
	pthread_join(thread, NULL);
	printf ("main %lu sorted array = ", me);
	print();
}

posted on 2022-10-15 13:38  20201310寸头  阅读(26)  评论(0编辑  收藏  举报