线程间同步之 semaphore(信号量)

semaphore 可用于进程间同步也可用于同一个进程间的线程同步。

semaphore 非常类似于mutex ,

共同点:semaphore和mutex都是内核对象,都可用于进程间的同步,并且都特别占用系统资源(线程的同步包括用户模式下的同步和内核模式下的同步,如果用内核对象来同步被保护的资源,系统需要从用户模式切换到内核模式,这个时间大概是1000个cpu周期)。

区别为:mutex只能由一个线程(进行)访问被保护的资源。semaphore 是一种带计数的mutex的锁定,可定义同时访问被保护的资源的线程数。

信号量有一个使用计数器,这个使用计数器,是信号量的最大资源计数和当前资源计数的差值。

信号量的规则如下:

a、如果当前资源计数大于0,那么信号量处于触发状态。

b、如果当前资源计数等于0,那么信号量处于未触发状态。

c、系统绝对不会让当前资源计数变为负数。

d、当前资源计数绝对不会大于最大最大资源计数

如:6个进程需要同时使用打印机,而电脑上只有四台打印机,则打印机是被保护的资源,信号量为4。则需要用semaphore来同步。

1、线程间的sempahore同步

使用下面的例子来讲解(见注释部分):

 1        static void Main(string[] args)
2 {
3 int threadCount = 6;
4 int sempaphoreCount = 4;
5 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了0个信号量
6 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
7 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(sempaphoreCount, sempaphoreCount, "sempaphore");
8
9 Thread[] threads = new Thread[threadCount];
10 for (int i = 0; i < threadCount; i++)
11 {
12 threads[i] = new Thread(ThreadMain);
13 threads[i].Start(sempaphore);
14 }
15 for (int i = 0; i < threadCount; i++)
16 {
17 threads[i].Join();
18 }
19 Console.WriteLine("All threads finished!");
20 Console.ReadKey();
21 }
22
23 /// <summary>
24 /// 线程执行的方法
25 /// </summary>
26 /// <param name="o"></param>
27 static void ThreadMain(object o)
28 {
29 Semaphore semaphore = o as Semaphore;
30 Trace.Assert(semaphore != null, "o must be a semphore type");
31
32 bool isCompleted = false;
33 while (!isCompleted)
34 {
35 //锁定信号量,如果锁定计数已经达到最高计数限制,则等待600毫秒。如果在600毫秒后未能获得锁定,则返回false。
36 if (semaphore.WaitOne(600, false))
37 {
38 try
39 {
40 Console.WriteLine("Thread {0} locks the semaphore ", Thread.CurrentThread.ManagedThreadId);
41 Thread.Sleep(2000);
42 }
43 finally
44 {
45 //解除资源的锁定。参数为退出信号量的次数。占用一个信号量故退出一个。
46 semaphore.Release(1);
47 Console.WriteLine("Thread {0} release the semaphore", Thread.CurrentThread.ManagedThreadId);
48 isCompleted = true;
49 }
50 }
51 else
52 {
53 Console.WriteLine("Timeot for thread {0}; wait again", Thread.CurrentThread.ManagedThreadId);
54 }
55 }
56 }

注意:如果出现 WaitOne 就一个要有对应的Release 即获取信号量后,一定要释放。

运行结果如下:

可以看到,四个线程(11、12、13、14)获得了锁定。线程15,16需要等待。该等待会重复进行,直到获得锁定的线程之一解除了信号量的锁定。

2、进程间的sempahore同步

下面的例子将使用信号量来同步进程,一个应用程序可以有二个实例运行(如果只允许有一个实例来运行,最优之选是mutex,其次才是信号量)。虽然这个例子不太实用,但完全可以说明semaphore的特性。

大家先看代码:

 1         static void Main(string[] args)
2 {
3 //定义可同步运行的可用实例数
4 int CreateNew = 2;
5
6 //定义可同步运行的最大实例数
7 int MaxCreateNew = 5;
8
9 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了3个信号量 计算方式为(MaxCreateNew-CreateNew)
10 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
11 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(CreateNew, MaxCreateNew, "sempaphoreProcess");
12
13 if (sempaphore.WaitOne(100, false))
14 {
15 Console.WriteLine("系统正在运行……");
16 Console.ReadKey();
17 }
18 else
19 {
20 MessageBox.Show("当前已经有 " + CreateNew + " 个实例在运行,系统将退出!", "您好", MessageBoxButtons.OK, MessageBoxIcon.Information);
21 }
22
23 }

生成解决方案后运行三次程序:

第一次运行和第二次运行结果如下:

第三次运行结果如下:

 现在已经完成只允许有两个应用程序实例在同时运行。

注意:信号量的进程同步和信号量的应用程序的名称无关。只要使用了同样名称的信号量,他们之前就存在了一种协约。

参考资料:c#高级编程


转载于:https://www.cnblogs.com/yuqilin/archive/2011/10/16/2214429.html

### MySQL 8.0 创建数据库教程 在 MySQL 8.0 中,创建数据库是一个基础的操作,可以通过 SQL 命令完成。以下是关于如何在 MySQL 8.0创建数据库的具体说明。 #### 数据库创建创建一个新的数据库,可以使用 `CREATE DATABASE` 或其同义词 `CREATE SCHEMA`[^3]。命令的基本语法如下: ```sql CREATE DATABASE IF NOT EXISTS databasename DEFAULT CHARACTER SET charset_name COLLATE collation_name; ``` 其中: - `IF NOT EXISTS` 是可选参数,用于防止重复创建数据库时引发错误。 - `charset_name` 和 `collation_name` 定义字符集及其排序规则,默认情况下会采用服务器配置中的默认值。 例如,如果希望创建名为 `testdb` 的数据库,并指定字符集为 UTF-8,则执行以下语句: ```sql CREATE DATABASE IF NOT EXISTS testdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` 此操作会在 MySQL 实例中生成一个名为 `testdb` 的数据库[^1]。 --- #### 用户的创建权限分配 为了安全起见,在创建数据库之后通常还需要创建相应的用户并赋予必要的权限。具体步骤如下: ##### 步骤一:创建用户 通过 `CREATE USER` 命令来定义新的用户账户。例如,创建一个名为 `testuser` 并允许从任意主机连接的用户: ```sql CREATE USER 'testuser'@'%' IDENTIFIED BY 'password'; ``` 此处 `'%'` 表示任何 IP 地址都可以访问该用户。如果仅限本地访问,可以用 `'localhost'` 替代 `%`[^2]。 ##### 步骤二:授予用户权限 利用 `GRANT` 命令向新建用户授予权限。假设需要让 `testuser` 对刚刚创建的 `testdb` 数据库拥有全部权限,运行以下指令: ```sql GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'%'; FLUSH PRIVILEGES; ``` 上述命令将使 `testuser` 能够完全控制 `testdb` 下的所有表结构和数据[^4]。 --- #### 总结代码实例 综合以上各部分,完整的脚本可能看起来像这样: ```sql -- 登录到 MySQL (需提前以 root 权限进入) mysql -u root -p -- 创建数据库 CREATE DATABASE IF NOT EXISTS testdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 创建用户 CREATE USER 'testuser'@'%' IDENTIFIED BY 'password'; -- 授予用户权限 GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'%'; FLUSH PRIVILEGES; ``` 这组命令实现了从无到有构建一个具备特定用户的独立数据库环境的过程。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值