校园服装网站建设预算,网站建设话术分析,做网站的公司主要工作,安全生产门户网站建设方案目录
1、信号量用于线程的互斥
验证
2、信号量用于线程的同步
验证
3、无名信号量用于进程间互斥
代码一
代码二
验证
4、有名信号量 用于进程间同步和互斥 验证 信号量广泛用于进程或线程间的同步和互斥#xff0c;信号量本质上是一个非负的整数计数器#xff0c;它…目录
1、信号量用于线程的互斥
验证
2、信号量用于线程的同步
验证
3、无名信号量用于进程间互斥
代码一
代码二
验证
4、有名信号量 用于进程间同步和互斥 验证 信号量广泛用于进程或线程间的同步和互斥信号量本质上是一个非负的整数计数器它被 用来控制对公共资源的访问。当信号量值大于 0 时则可以访问否则将阻塞。信号量是一种用于控制进程或线程同步和互斥的机制。它通常由一个计数器和一组等待的进程或线程组成。当进程或线程需要访问共享资源时它会尝试获取一个信号量。如果信号量的计数器大于0则进程或线程可以获得信号量并继续执行。否则进程或线程将被阻塞直到有信号量可用。 PV 原语是对信号量的操作一次 P 操作使信号量减一次 V 操作使信号量加。 信号量数据类型为sem_t
1、信号量用于线程的互斥
#include stdio.h
#include pthread.h
#include semaphore.h
#include unistd.h// 定义一个信号量(用于互斥)
sem_t sem;void my_printf(char *str)
{int i 0;while (str[i] ! \0){printf(%c, str[i]);fflush(stdout);sleep(1);}
}
void *fun1(void *arg)
{// P 操作sem_wait(sem);my_printf((char *)arg);// V 操作sem_post(sem);
}
void *fun2(void *arg)
{// P 操作sem_wait(sem);my_printf((char *)arg);// V 操作sem_post(sem);
}
void *fun3(void *arg)
{// P 操作sem_wait(sem);my_printf((char *)arg);// V 操作sem_post(sem);
}
int main(int argc, char *argv[])
{// 信号量初始化为1 第二个参数0表示用于线程,第三个信号量初始值sem_init(sem, 0, 1);pthread_t tid1, tid2, tid3;pthread_create(tid1, NULL, fun1, this is tid1\n);pthread_create(tid2, NULL, fun2, this is tid2\n);pthread_create(tid3, NULL, fun3, this is tid3\n);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);//销毁信号量sem_destroy(sem);return 0;
} 实现了三个线程的并发输出但是通过信号量sem保证了只有一个线程在输出时访问标准输出流即实现了互斥。 定义了一个信号量 sem 用于实现互斥访问。三个线程 tid1、tid2 和 tid3 将同时运行它们的目标是调用 my_printf 函数打印不同的字符串但是这些线程之间需要互斥访问共享资源否则会导致输出的字符串混乱。 在 fun1、fun2 和 fun3 函数中首先调用 sem_wait 函数来申请信号量资源表示进入临界区如果信号量的值为1则将其减1表示申请成功否则阻塞等待。然后调用 my_printf 函数输出相应的字符串最后调用 sem_post 函数释放信号量资源将其加1表示退出临界区其他线程就可以申请这个资源了。 主函数中初始化了信号量创建三个线程分别调用 fun1、fun2 和 fun3 函数最后等待三个线程执行结束销毁信号量。
验证 线程的执行顺序是不确定的由操作系统决定。虽然代码中是先创建tid1线程但是操作系统可能会优先执行tid3线程所以最终的执行结果可能是tid3先执行然后是tid2最后是tid1。因此不能依赖代码中的线程创建顺序来确定线程的执行顺序。
2、信号量用于线程的同步
#include stdio.h
#include pthread.h
#include semaphore.h
#include unistd.h// 定义三个信号量(用于同步)
sem_t sem1, sem2, sem3;
void my_printf(char *str)
{int i 0;while (str[i] ! \0){printf(%c, str[i]);fflush(stdout);sleep(1);}
}
void *syn_fun1(void *arg)
{ // psem_wait(sem1);my_printf((char *)arg);// vsem_post(sem2);
}
void *syn_fun2(void *arg)
{ // psem_wait(sem2);my_printf((char *)arg);// vsem_post(sem3);
}
void *syn_fun3(void *arg)
{ // psem_wait(sem3);my_printf((char *)arg);// vsem_post(sem1);
}
int main(int argc, char *argv[])
{// 信号量初始化为1 第二个参数0表示用于线程sem_init(sem1, 0, 1);sem_init(sem2, 0, 0);sem_init(sem3, 0, 0);pthread_t tid1, tid2, tid3;pthread_create(tid1, NULL, syn_fun1, this is tid1\n);pthread_create(tid2, NULL, syn_fun2, this is tid2\n);pthread_create(tid3, NULL, syn_fun3, this is tid3\n);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);// 销毁信号量sem_destroy(sem1);sem_destroy(sem2);sem_destroy(sem3);return 0;
} 实现了三个线程的同步执行即按照指定的顺序依次输出三个字符串。其中使用了三个信号量来实现同步分别为sem1、sem2、sem3。这三个信号量的初始值分别为1、0、0表示sem1可以被访问而sem2和sem3需要等待其他线程的信号才能被访问。三个线程分别对应syn_fun1、syn_fun2、syn_fun3函数每个函数中都使用了sem_wait和sem_post来对信号量进行操作。其中sem_wait用于P操作即尝试获取信号量如果信号量的值为0则线程会阻塞等待其他线程的信号而sem_post用于V操作即释放信号量将信号量的值加1表示其他线程可以访问这个信号量了。最后在main函数中创建三个线程并使用pthread_join等待线程结束最后销毁信号量。
验证 虽然定义了三个信号量但是初始值为1的信号量只有一个所以只有为1的信号量对应的sem1能运行其他的需要等待信号也就确保了只有tid1先运行不会像上面互斥一样随机运行
3、无名信号量用于进程间互斥 无名信号量是一种特殊类型的信号量它只能被同一进程内的线程使用。它们不需要被命名因此被称为“无名信号量”。无名信号量通常用于控制线程之间的同步和互斥。在代码示例中sem_init 函数用于初始化一个无名信号量而 sem_wait 和 sem_post 函数分别用于等待和释放信号量。
代码一
#include stdio.h
#include semaphore.h
#include unistd.h
#include sys/mman.hvoid my_printf(char *str)
{int i 0;while (str[i] ! \0)printf(%c, str[i]);fflush(stdout);sleep(1);
}
int main(int argc, char *argv[])
{// 定义一个无名信号量// MAP_ANONYMOUS匿名映射 ‐1不需要文件描述符sem_t *sem mmap(NULL,sizeof(sem_t),PROT_READ |PROT_WRITE,MAP_SHARED |MAP_ANONYMOUS,-1, 0);// 无名信号量的初始化 第一个1表示进程 第二个1表示初始化值1sem_init(sem, 1, 1);pid_t pid fork();if (pid 0) // 子进程{// psem_wait(sem);my_printf(child process\n);// vsem_post(sem);}else if (pid 0) // 父进程{// psem_wait(sem);my_printf(father process\n);// vsem_post(sem);}sem_destroy(sem);return 0;
} 通过调用mmap函数将信号量映射到进程的虚拟内存空间中。然后使用sem_init初始化信号量的值为1表示当前没有其他进程在访问它。接着通过调用fork函数创建一个子进程。在父进程中调用sem_wait函数尝试获得对信号量的访问权。由于这是第一个进程因此它能够获得对信号量的访问权。它打印一条消息然后使用sem_post函数释放对信号量的访问权。在子进程中它也会尝试获得对信号量的访问权但是由于父进程已经获得了对信号量的访问权所以子进程必须等待父进程释放对信号量的访问权。然后它打印一条消息再次使用sem_post函数释放对信号量的访问权。最后调用sem_destroy函数销毁信号量并释放资源。 mmap是一个系统调用用于将一个文件或设备映射到内存中。在上面的代码中它的作用是为共享内存分配一块内存区域返回的是指向这个区域的指针。mmap函数的调用参数解释如下
NULL表示分配内存区域的起始地址由系统自动分配sizeof(sem_t)表示需要分配的内存区域的大小PROT_READ | PROT_WRITE表示内存区域的访问权限这里是可读可写MAP_SHARED表示这块内存区域是被多个进程共享的,使用了 MAP_ANONYMOUS 标志来创建一个匿名映射一个无名的共享内存区域,不需要与文件关联fd表示文件描述符这里是共享内存的文件描述符,‐1不需要文件描述符0表示偏移量这里没有偏移从文件开头开始映射成功 返回映射区的首地址
代码二
#include stdio.h
#include semaphore.h
#include unistd.h
#include sys/mman.hvoid my_printf(char *str)
{int i0;while(str[i] ! \0){printf(%c, str[i]);fflush(stdout);sleep(1);}
}
int main(int argc, char *argv[])
{//定义一个无名信号量//MAP_ANONYMOUS匿名映射 ‐1不需要文件描述符sem_t *sem1 mmap(NULL, sizeof(sem_t),PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);sem_t *sem2 mmap(NULL, sizeof(sem_t),PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);//无名信号量的初始化 第一个1表示进程 第二个1表示初始化值1sem_init(sem1,1,1);sem_init(sem2,1,0);pid_t pid fork();if(pid 0)//子进程{//psem_wait(sem1);my_printf(this is child process\n);//vsem_post(sem2);}else if(pid 0){//psem_wait(sem2);my_printf(this is father process\n);//vsem_post(sem1);}//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;} 这段代码定义了两个无名信号量sem1和sem2并使用mmap将它们分别映射到了进程的虚拟内存空间中。然后使用这两个无名信号量实现了进程间的同步。不同于前面那段代码这段代码使用了两个不同的指针变量sem1和sem2分别指向映射到内存中的两个无名信号量。同时在创建子进程时子进程通过sem2来等待父进程打开它父进程通过sem1来等待子进程打开它。这样就实现了进程间的同步。总的来说这两段代码使用的都是无名信号量来实现进程间同步只不过一个使用了一个无名信号量另一个使用了两个无名信号量来实现。
验证 两段代码结果打印的都是相同的信息
4、有名信号量 用于进程间同步和互斥
#include stdio.h
#include semaphore.h
#include unistd.h
#include fcntl.h
#include sys/stat.h
void my_printf(char *str)
{int i 0;while (str[i] ! \0){printf(%c, str[i]);fflush(stdout);sleep(1);}
}int main(int argc, char **argv)
{// 创建2个有名信号量sem_open 最后一个参数为初始值sem_t *sem1 sem_open(sem1, O_RDWR | O_CREAT, 0666, 1);sem_t *sem2 sem_open(sem2, O_RDWR | O_CREAT, 0666,0);// psem_wait(sem1);// 任务my_printf(this is sem1\n);// vsem_post(sem2);// 任务my_printf(this is sem2\n);//psem_post(sem1);// 关闭信号量sem_close(sem1);sem_close(sem2);// 销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
} 进程通过sem_wait(sem1)获取sem1信号量如果此时sem1的值为1则将其减1表示占用资源否则阻塞等待。进程输出this is sem1\n此时其他进程无法获得sem1信号量从而实现了互斥。进程通过sem_post(sem2)释放sem2信号量将其值加1唤醒其他阻塞在sem2上的进程从而实现了同步。此时其他进程可以获取sem2信号量进行下一步操作。进程输出this is sem2\n其他进程无法获取sem2信号量从而实现了互斥。 在第二个任务执行完毕之后调用sem_post(sem1)将sem1的值加一此时又可以重新进入第一个任务。这种方式可以保证第一个任务和第二个任务的执行顺序并且在第二个任务执行完毕之前第一个任务不会被重新执行。同时由于sem1的初始值为1保证了只有一个进程可以访问第一个任务的代码实现了互斥 验证